From d18cdea19b5deaf475255c4552fb18438842a8ad Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Wed, 10 Dec 2025 08:35:25 +0100 Subject: [PATCH 01/18] VPN Service --- go.mod | 9 +- go.sum | 18 +- pkg/request/tokenpermissions_test.go | 683 +++++++++++----------- pkg/service/vpn/admin/vpn-service.go | 125 ++++ pkg/service/vpn/admin/vpn-service_test.go | 89 +++ pkg/test/headscale-config.yaml | 106 ++++ pkg/test/headscale.go | 99 ++++ 7 files changed, 776 insertions(+), 353 deletions(-) create mode 100644 pkg/service/vpn/admin/vpn-service.go create mode 100644 pkg/service/vpn/admin/vpn-service_test.go create mode 100644 pkg/test/headscale-config.yaml create mode 100644 pkg/test/headscale.go diff --git a/go.mod b/go.mod index 0b0d12bb..cb3b1a39 100644 --- a/go.mod +++ b/go.mod @@ -21,10 +21,11 @@ require ( github.com/gorilla/sessions v1.4.0 github.com/hibiken/asynq v0.25.1 github.com/jmoiron/sqlx v1.4.0 + github.com/juanfont/headscale v0.27.1 github.com/klauspost/connect-compress/v2 v2.1.0 github.com/lestrrat-go/jwx/v3 v3.0.12 github.com/markbates/goth v1.82.0 - github.com/metal-stack/api v0.0.35 + github.com/metal-stack/api v0.0.36-0.20251210073043-abfdf6fa173a github.com/metal-stack/go-ipam v1.14.13 github.com/metal-stack/masterdata-api v0.13.0 github.com/metal-stack/metal-lib v0.23.5 @@ -58,7 +59,6 @@ require ( github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect @@ -69,6 +69,7 @@ require ( github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect + github.com/creack/pty v1.1.23 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect @@ -181,10 +182,10 @@ require ( go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.45.0 // indirect - golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 // indirect + golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sys v0.39.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect diff --git a/go.sum b/go.sum index 32ab0ed1..7159fc09 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHf github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= +github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -229,6 +229,8 @@ github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/juanfont/headscale v0.27.1 h1:BSvxiQX3GBgLUrAO3fpYnftnBUAUqgLkZVpS4G+b82c= +github.com/juanfont/headscale v0.27.1/go.mod h1:MD56ISg1SHt7NvnzOCAt+CIBnDmzftxTknbElPHkfc0= 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.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= @@ -279,8 +281,8 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 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/metal-stack/api v0.0.35 h1:XxxYKTscSeYJg/ftL519nY3FAZ01atPeyD7+Zz/amQQ= -github.com/metal-stack/api v0.0.35/go.mod h1:EBwS/oZr5tIcnV6hM7iK4aBQrw4wlU7vF5p+O1p3YIU= +github.com/metal-stack/api v0.0.36-0.20251210073043-abfdf6fa173a h1:bghLv594/MwdYVZXD54NRgiuTfCSOM7KNf0Q3eh5kR0= +github.com/metal-stack/api v0.0.36-0.20251210073043-abfdf6fa173a/go.mod h1:ksr+C/um5Q10t9FnC9UuQ1LvgH7Qsw1c0IwSbvWRfyE= github.com/metal-stack/go-ipam v1.14.13 h1:/W5/MDBX5EU18xNDjlBvV6JjQ1Ot12dO2WxLvV6S8vc= github.com/metal-stack/go-ipam v1.14.13/go.mod h1:eif3UGUFP7CWJdrgLIOjhVM3G2K19GN8lhCgPVfvLDs= github.com/metal-stack/masterdata-api v0.13.0 h1:1AxnsiWiTMstjMsphZ0wMFT7aW3QQhAMumXnQ81PtHk= @@ -475,8 +477,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY= -golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -522,8 +524,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/pkg/request/tokenpermissions_test.go b/pkg/request/tokenpermissions_test.go index cfc45885..9a144238 100644 --- a/pkg/request/tokenpermissions_test.go +++ b/pkg/request/tokenpermissions_test.go @@ -30,11 +30,11 @@ func Test_getTokenPermissions(t *testing.T) { name: "empty token", token: nil, want: tokenPermissions{ - "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo": {"*": entry{}}, - "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": {"*": entry{}}, - "/metalstack.api.v2.HealthService/Get": {"*": entry{}}, - "/metalstack.api.v2.MethodService/List": {"*": entry{}}, - "/metalstack.api.v2.VersionService/Get": {"*": entry{}}, + "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo": {"*": {}}, + "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": {"*": {}}, + "/metalstack.api.v2.HealthService/Get": {"*": {}}, + "/metalstack.api.v2.MethodService/List": {"*": {}}, + "/metalstack.api.v2.VersionService/Get": {"*": {}}, }, }, { @@ -45,109 +45,110 @@ func Test_getTokenPermissions(t *testing.T) { AdminRole: apiv2.AdminRole_ADMIN_ROLE_EDITOR.Enum(), }, want: tokenPermissions{ - "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo": {"*": entry{}}, - "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": {"*": entry{}}, - "/metalstack.admin.v2.FilesystemService/Create": {"*": entry{}}, - "/metalstack.admin.v2.FilesystemService/Delete": {"*": entry{}}, - "/metalstack.admin.v2.FilesystemService/Update": {"*": entry{}}, - "/metalstack.admin.v2.IPService/List": {"*": entry{}}, - "/metalstack.admin.v2.ImageService/Create": {"*": entry{}}, - "/metalstack.admin.v2.ImageService/Delete": {"*": entry{}}, - "/metalstack.admin.v2.ImageService/Update": {"*": entry{}}, - "/metalstack.admin.v2.ImageService/Usage": {"*": entry{}}, - "/metalstack.admin.v2.MachineService/Get": {"*": entry{}}, - "/metalstack.admin.v2.MachineService/List": {"*": entry{}}, - "/metalstack.admin.v2.NetworkService/Create": {"*": entry{}}, - "/metalstack.admin.v2.NetworkService/Delete": {"*": entry{}}, - "/metalstack.admin.v2.NetworkService/Get": {"*": entry{}}, - "/metalstack.admin.v2.NetworkService/List": {"*": entry{}}, - "/metalstack.admin.v2.NetworkService/Update": {"*": entry{}}, - "/metalstack.admin.v2.PartitionService/Capacity": {"*": entry{}}, - "/metalstack.admin.v2.PartitionService/Create": {"*": entry{}}, - "/metalstack.admin.v2.PartitionService/Delete": {"*": entry{}}, - "/metalstack.admin.v2.PartitionService/Update": {"*": entry{}}, - "/metalstack.admin.v2.ProjectService/List": {"*": entry{}}, - "/metalstack.admin.v2.SizeService/Create": {"*": entry{}}, - "/metalstack.admin.v2.SizeService/Delete": {"*": entry{}}, - "/metalstack.admin.v2.SizeService/Update": {"*": entry{}}, - "/metalstack.admin.v2.SwitchService/Delete": {"*": entry{}}, - "/metalstack.admin.v2.SwitchService/Get": {"*": entry{}}, - "/metalstack.admin.v2.SwitchService/List": {"*": entry{}}, - "/metalstack.admin.v2.SwitchService/Migrate": {"*": entry{}}, - "/metalstack.admin.v2.SwitchService/Port": {"*": entry{}}, - "/metalstack.admin.v2.SwitchService/Update": {"*": entry{}}, - "/metalstack.admin.v2.TenantService/Create": {"*": entry{}}, - "/metalstack.admin.v2.TenantService/List": {"*": entry{}}, - "/metalstack.admin.v2.TokenService/Create": {"*": entry{}}, - "/metalstack.admin.v2.TokenService/List": {"*": entry{}}, - "/metalstack.admin.v2.TokenService/Revoke": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/Get": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/List": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/Match": {"*": entry{}}, - "/metalstack.api.v2.HealthService/Get": {"*": entry{}}, - "/metalstack.api.v2.IPService/Create": {"*": entry{}}, - "/metalstack.api.v2.IPService/Delete": {"*": entry{}}, - "/metalstack.api.v2.IPService/Get": {"*": entry{}}, - "/metalstack.api.v2.IPService/List": {"*": entry{}}, - "/metalstack.api.v2.IPService/Update": {"*": entry{}}, - "/metalstack.api.v2.ImageService/Get": {"*": entry{}}, - "/metalstack.api.v2.ImageService/Latest": {"*": entry{}}, - "/metalstack.api.v2.ImageService/List": {"*": entry{}}, - "/metalstack.api.v2.MachineService/Create": {"*": entry{}}, - "/metalstack.api.v2.MachineService/Delete": {"*": entry{}}, - "/metalstack.api.v2.MachineService/Get": {"*": entry{}}, - "/metalstack.api.v2.MachineService/List": {"*": entry{}}, - "/metalstack.api.v2.MachineService/Update": {"*": entry{}}, - "/metalstack.api.v2.MethodService/List": {"*": entry{}}, - "/metalstack.api.v2.MethodService/TokenScopedList": {"*": entry{}}, - "/metalstack.api.v2.NetworkService/Create": {"*": entry{}}, - "/metalstack.api.v2.NetworkService/Delete": {"*": entry{}}, - "/metalstack.api.v2.NetworkService/Get": {"*": entry{}}, - "/metalstack.api.v2.NetworkService/List": {"*": entry{}}, - "/metalstack.api.v2.NetworkService/ListBaseNetworks": {"*": entry{}}, - "/metalstack.api.v2.NetworkService/Update": {"*": entry{}}, - "/metalstack.api.v2.PartitionService/Get": {"*": entry{}}, - "/metalstack.api.v2.PartitionService/List": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/Create": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/Delete": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/Get": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/Invite": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/InviteAccept": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/InviteDelete": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/InviteGet": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/InvitesList": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/Leave": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/List": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/RemoveMember": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/Update": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/UpdateMember": {"*": entry{}}, - "/metalstack.api.v2.SizeService/Get": {"*": entry{}}, - "/metalstack.api.v2.SizeService/List": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Create": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Delete": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Get": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Invite": {"*": entry{}}, - "/metalstack.api.v2.TenantService/InviteAccept": {"*": entry{}}, - "/metalstack.api.v2.TenantService/InviteDelete": {"*": entry{}}, - "/metalstack.api.v2.TenantService/InviteGet": {"*": entry{}}, - "/metalstack.api.v2.TenantService/InvitesList": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Leave": {"*": entry{}}, - "/metalstack.api.v2.TenantService/List": {"*": entry{}}, - "/metalstack.api.v2.TenantService/RemoveMember": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Update": {"*": entry{}}, - "/metalstack.api.v2.TenantService/UpdateMember": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Create": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Get": {"*": entry{}}, - "/metalstack.api.v2.TokenService/List": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Refresh": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Revoke": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Update": {"*": entry{}}, - "/metalstack.api.v2.UserService/Get": {"*": entry{}}, - "/metalstack.api.v2.VersionService/Get": {"*": entry{}}, - "/metalstack.infra.v2.BMCService/UpdateBMCInfo": {"*": entry{}}, - "/metalstack.infra.v2.SwitchService/Get": {"*": entry{}}, - "/metalstack.infra.v2.SwitchService/Heartbeat": {"*": entry{}}, - "/metalstack.infra.v2.SwitchService/Register": {"*": entry{}}, + "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo": {"*": {}}, + "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": {"*": {}}, + "/metalstack.admin.v2.FilesystemService/Create": {"*": {}}, + "/metalstack.admin.v2.FilesystemService/Delete": {"*": {}}, + "/metalstack.admin.v2.FilesystemService/Update": {"*": {}}, + "/metalstack.admin.v2.IPService/List": {"*": {}}, + "/metalstack.admin.v2.ImageService/Create": {"*": {}}, + "/metalstack.admin.v2.ImageService/Delete": {"*": {}}, + "/metalstack.admin.v2.ImageService/Update": {"*": {}}, + "/metalstack.admin.v2.ImageService/Usage": {"*": {}}, + "/metalstack.admin.v2.MachineService/Get": {"*": {}}, + "/metalstack.admin.v2.MachineService/List": {"*": {}}, + "/metalstack.admin.v2.NetworkService/Create": {"*": {}}, + "/metalstack.admin.v2.NetworkService/Delete": {"*": {}}, + "/metalstack.admin.v2.NetworkService/Get": {"*": {}}, + "/metalstack.admin.v2.NetworkService/List": {"*": {}}, + "/metalstack.admin.v2.NetworkService/Update": {"*": {}}, + "/metalstack.admin.v2.PartitionService/Capacity": {"*": {}}, + "/metalstack.admin.v2.PartitionService/Create": {"*": {}}, + "/metalstack.admin.v2.PartitionService/Delete": {"*": {}}, + "/metalstack.admin.v2.PartitionService/Update": {"*": {}}, + "/metalstack.admin.v2.ProjectService/List": {"*": {}}, + "/metalstack.admin.v2.SizeService/Create": {"*": {}}, + "/metalstack.admin.v2.SizeService/Delete": {"*": {}}, + "/metalstack.admin.v2.SizeService/Update": {"*": {}}, + "/metalstack.admin.v2.SwitchService/Delete": {"*": {}}, + "/metalstack.admin.v2.SwitchService/Get": {"*": {}}, + "/metalstack.admin.v2.SwitchService/List": {"*": {}}, + "/metalstack.admin.v2.SwitchService/Migrate": {"*": {}}, + "/metalstack.admin.v2.SwitchService/Port": {"*": {}}, + "/metalstack.admin.v2.SwitchService/Update": {"*": {}}, + "/metalstack.admin.v2.TenantService/Create": {"*": {}}, + "/metalstack.admin.v2.TenantService/List": {"*": {}}, + "/metalstack.admin.v2.TokenService/Create": {"*": {}}, + "/metalstack.admin.v2.TokenService/List": {"*": {}}, + "/metalstack.admin.v2.TokenService/Revoke": {"*": {}}, + "/metalstack.admin.v2.VPNService/Authkey": {"*": {}}, + "/metalstack.api.v2.FilesystemService/Get": {"*": {}}, + "/metalstack.api.v2.FilesystemService/List": {"*": {}}, + "/metalstack.api.v2.FilesystemService/Match": {"*": {}}, + "/metalstack.api.v2.HealthService/Get": {"*": {}}, + "/metalstack.api.v2.IPService/Create": {"*": {}}, + "/metalstack.api.v2.IPService/Delete": {"*": {}}, + "/metalstack.api.v2.IPService/Get": {"*": {}}, + "/metalstack.api.v2.IPService/List": {"*": {}}, + "/metalstack.api.v2.IPService/Update": {"*": {}}, + "/metalstack.api.v2.ImageService/Get": {"*": {}}, + "/metalstack.api.v2.ImageService/Latest": {"*": {}}, + "/metalstack.api.v2.ImageService/List": {"*": {}}, + "/metalstack.api.v2.MachineService/Create": {"*": {}}, + "/metalstack.api.v2.MachineService/Delete": {"*": {}}, + "/metalstack.api.v2.MachineService/Get": {"*": {}}, + "/metalstack.api.v2.MachineService/List": {"*": {}}, + "/metalstack.api.v2.MachineService/Update": {"*": {}}, + "/metalstack.api.v2.MethodService/List": {"*": {}}, + "/metalstack.api.v2.MethodService/TokenScopedList": {"*": {}}, + "/metalstack.api.v2.NetworkService/Create": {"*": {}}, + "/metalstack.api.v2.NetworkService/Delete": {"*": {}}, + "/metalstack.api.v2.NetworkService/Get": {"*": {}}, + "/metalstack.api.v2.NetworkService/List": {"*": {}}, + "/metalstack.api.v2.NetworkService/ListBaseNetworks": {"*": {}}, + "/metalstack.api.v2.NetworkService/Update": {"*": {}}, + "/metalstack.api.v2.PartitionService/Get": {"*": {}}, + "/metalstack.api.v2.PartitionService/List": {"*": {}}, + "/metalstack.api.v2.ProjectService/Create": {"*": {}}, + "/metalstack.api.v2.ProjectService/Delete": {"*": {}}, + "/metalstack.api.v2.ProjectService/Get": {"*": {}}, + "/metalstack.api.v2.ProjectService/Invite": {"*": {}}, + "/metalstack.api.v2.ProjectService/InviteAccept": {"*": {}}, + "/metalstack.api.v2.ProjectService/InviteDelete": {"*": {}}, + "/metalstack.api.v2.ProjectService/InviteGet": {"*": {}}, + "/metalstack.api.v2.ProjectService/InvitesList": {"*": {}}, + "/metalstack.api.v2.ProjectService/Leave": {"*": {}}, + "/metalstack.api.v2.ProjectService/List": {"*": {}}, + "/metalstack.api.v2.ProjectService/RemoveMember": {"*": {}}, + "/metalstack.api.v2.ProjectService/Update": {"*": {}}, + "/metalstack.api.v2.ProjectService/UpdateMember": {"*": {}}, + "/metalstack.api.v2.SizeService/Get": {"*": {}}, + "/metalstack.api.v2.SizeService/List": {"*": {}}, + "/metalstack.api.v2.TenantService/Create": {"*": {}}, + "/metalstack.api.v2.TenantService/Delete": {"*": {}}, + "/metalstack.api.v2.TenantService/Get": {"*": {}}, + "/metalstack.api.v2.TenantService/Invite": {"*": {}}, + "/metalstack.api.v2.TenantService/InviteAccept": {"*": {}}, + "/metalstack.api.v2.TenantService/InviteDelete": {"*": {}}, + "/metalstack.api.v2.TenantService/InviteGet": {"*": {}}, + "/metalstack.api.v2.TenantService/InvitesList": {"*": {}}, + "/metalstack.api.v2.TenantService/Leave": {"*": {}}, + "/metalstack.api.v2.TenantService/List": {"*": {}}, + "/metalstack.api.v2.TenantService/RemoveMember": {"*": {}}, + "/metalstack.api.v2.TenantService/Update": {"*": {}}, + "/metalstack.api.v2.TenantService/UpdateMember": {"*": {}}, + "/metalstack.api.v2.TokenService/Create": {"*": {}}, + "/metalstack.api.v2.TokenService/Get": {"*": {}}, + "/metalstack.api.v2.TokenService/List": {"*": {}}, + "/metalstack.api.v2.TokenService/Refresh": {"*": {}}, + "/metalstack.api.v2.TokenService/Revoke": {"*": {}}, + "/metalstack.api.v2.TokenService/Update": {"*": {}}, + "/metalstack.api.v2.UserService/Get": {"*": {}}, + "/metalstack.api.v2.VersionService/Get": {"*": {}}, + "/metalstack.infra.v2.BMCService/UpdateBMCInfo": {"*": {}}, + "/metalstack.infra.v2.SwitchService/Get": {"*": {}}, + "/metalstack.infra.v2.SwitchService/Heartbeat": {"*": {}}, + "/metalstack.infra.v2.SwitchService/Register": {"*": {}}, }, wantErr: nil, }, @@ -159,60 +160,60 @@ func Test_getTokenPermissions(t *testing.T) { AdminRole: apiv2.AdminRole_ADMIN_ROLE_VIEWER.Enum(), }, want: tokenPermissions{ - "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo": {"*": entry{}}, - "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": {"*": entry{}}, - "/metalstack.admin.v2.IPService/List": {"*": entry{}}, - "/metalstack.admin.v2.ImageService/Usage": {"*": entry{}}, - "/metalstack.admin.v2.MachineService/Get": {"*": entry{}}, - "/metalstack.admin.v2.MachineService/List": {"*": entry{}}, - "/metalstack.admin.v2.NetworkService/Get": {"*": entry{}}, - "/metalstack.admin.v2.NetworkService/List": {"*": entry{}}, - "/metalstack.admin.v2.PartitionService/Capacity": {"*": entry{}}, - "/metalstack.admin.v2.ProjectService/List": {"*": entry{}}, - "/metalstack.admin.v2.SwitchService/Get": {"*": entry{}}, - "/metalstack.admin.v2.SwitchService/List": {"*": entry{}}, - "/metalstack.admin.v2.TenantService/List": {"*": entry{}}, - "/metalstack.admin.v2.TokenService/List": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/Get": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/List": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/Match": {"*": entry{}}, - "/metalstack.api.v2.HealthService/Get": {"*": entry{}}, - "/metalstack.api.v2.IPService/Get": {"*": entry{}}, - "/metalstack.api.v2.IPService/List": {"*": entry{}}, - "/metalstack.api.v2.ImageService/Get": {"*": entry{}}, - "/metalstack.api.v2.ImageService/Latest": {"*": entry{}}, - "/metalstack.api.v2.ImageService/List": {"*": entry{}}, - "/metalstack.api.v2.MachineService/Get": {"*": entry{}}, - "/metalstack.api.v2.MachineService/List": {"*": entry{}}, - "/metalstack.api.v2.MethodService/List": {"*": entry{}}, - "/metalstack.api.v2.MethodService/TokenScopedList": {"*": entry{}}, - "/metalstack.api.v2.NetworkService/Get": {"*": entry{}}, - "/metalstack.api.v2.NetworkService/List": {"*": entry{}}, - "/metalstack.api.v2.NetworkService/ListBaseNetworks": {"*": entry{}}, - "/metalstack.api.v2.PartitionService/Get": {"*": entry{}}, - "/metalstack.api.v2.PartitionService/List": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/Get": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/InviteAccept": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/InviteGet": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/Leave": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/List": {"*": entry{}}, - "/metalstack.api.v2.SizeService/Get": {"*": entry{}}, - "/metalstack.api.v2.SizeService/List": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Create": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Get": {"*": entry{}}, - "/metalstack.api.v2.TenantService/InviteAccept": {"*": entry{}}, - "/metalstack.api.v2.TenantService/InviteGet": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Leave": {"*": entry{}}, - "/metalstack.api.v2.TenantService/List": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Create": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Get": {"*": entry{}}, - "/metalstack.api.v2.TokenService/List": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Refresh": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Revoke": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Update": {"*": entry{}}, - "/metalstack.api.v2.UserService/Get": {"*": entry{}}, - "/metalstack.api.v2.VersionService/Get": {"*": entry{}}, - "/metalstack.infra.v2.SwitchService/Get": {"*": entry{}}, + "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo": {"*": {}}, + "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": {"*": {}}, + "/metalstack.admin.v2.IPService/List": {"*": {}}, + "/metalstack.admin.v2.ImageService/Usage": {"*": {}}, + "/metalstack.admin.v2.MachineService/Get": {"*": {}}, + "/metalstack.admin.v2.MachineService/List": {"*": {}}, + "/metalstack.admin.v2.NetworkService/Get": {"*": {}}, + "/metalstack.admin.v2.NetworkService/List": {"*": {}}, + "/metalstack.admin.v2.PartitionService/Capacity": {"*": {}}, + "/metalstack.admin.v2.ProjectService/List": {"*": {}}, + "/metalstack.admin.v2.SwitchService/Get": {"*": {}}, + "/metalstack.admin.v2.SwitchService/List": {"*": {}}, + "/metalstack.admin.v2.TenantService/List": {"*": {}}, + "/metalstack.admin.v2.TokenService/List": {"*": {}}, + "/metalstack.api.v2.FilesystemService/Get": {"*": {}}, + "/metalstack.api.v2.FilesystemService/List": {"*": {}}, + "/metalstack.api.v2.FilesystemService/Match": {"*": {}}, + "/metalstack.api.v2.HealthService/Get": {"*": {}}, + "/metalstack.api.v2.IPService/Get": {"*": {}}, + "/metalstack.api.v2.IPService/List": {"*": {}}, + "/metalstack.api.v2.ImageService/Get": {"*": {}}, + "/metalstack.api.v2.ImageService/Latest": {"*": {}}, + "/metalstack.api.v2.ImageService/List": {"*": {}}, + "/metalstack.api.v2.MachineService/Get": {"*": {}}, + "/metalstack.api.v2.MachineService/List": {"*": {}}, + "/metalstack.api.v2.MethodService/List": {"*": {}}, + "/metalstack.api.v2.MethodService/TokenScopedList": {"*": {}}, + "/metalstack.api.v2.NetworkService/Get": {"*": {}}, + "/metalstack.api.v2.NetworkService/List": {"*": {}}, + "/metalstack.api.v2.NetworkService/ListBaseNetworks": {"*": {}}, + "/metalstack.api.v2.PartitionService/Get": {"*": {}}, + "/metalstack.api.v2.PartitionService/List": {"*": {}}, + "/metalstack.api.v2.ProjectService/Get": {"*": {}}, + "/metalstack.api.v2.ProjectService/InviteAccept": {"*": {}}, + "/metalstack.api.v2.ProjectService/InviteGet": {"*": {}}, + "/metalstack.api.v2.ProjectService/Leave": {"*": {}}, + "/metalstack.api.v2.ProjectService/List": {"*": {}}, + "/metalstack.api.v2.SizeService/Get": {"*": {}}, + "/metalstack.api.v2.SizeService/List": {"*": {}}, + "/metalstack.api.v2.TenantService/Create": {"*": {}}, + "/metalstack.api.v2.TenantService/Get": {"*": {}}, + "/metalstack.api.v2.TenantService/InviteAccept": {"*": {}}, + "/metalstack.api.v2.TenantService/InviteGet": {"*": {}}, + "/metalstack.api.v2.TenantService/Leave": {"*": {}}, + "/metalstack.api.v2.TenantService/List": {"*": {}}, + "/metalstack.api.v2.TokenService/Create": {"*": {}}, + "/metalstack.api.v2.TokenService/Get": {"*": {}}, + "/metalstack.api.v2.TokenService/List": {"*": {}}, + "/metalstack.api.v2.TokenService/Refresh": {"*": {}}, + "/metalstack.api.v2.TokenService/Revoke": {"*": {}}, + "/metalstack.api.v2.TokenService/Update": {"*": {}}, + "/metalstack.api.v2.UserService/Get": {"*": {}}, + "/metalstack.api.v2.VersionService/Get": {"*": {}}, + "/metalstack.infra.v2.SwitchService/Get": {"*": {}}, }, wantErr: nil, }, @@ -224,10 +225,10 @@ func Test_getTokenPermissions(t *testing.T) { InfraRole: apiv2.InfraRole_INFRA_ROLE_EDITOR.Enum(), }, want: tokenPermissions{ - "/metalstack.infra.v2.BMCService/UpdateBMCInfo": {"*": entry{}}, - "/metalstack.infra.v2.SwitchService/Get": {"*": entry{}}, - "/metalstack.infra.v2.SwitchService/Heartbeat": {"*": entry{}}, - "/metalstack.infra.v2.SwitchService/Register": {"*": entry{}}, + "/metalstack.infra.v2.BMCService/UpdateBMCInfo": {"*": {}}, + "/metalstack.infra.v2.SwitchService/Get": {"*": {}}, + "/metalstack.infra.v2.SwitchService/Heartbeat": {"*": {}}, + "/metalstack.infra.v2.SwitchService/Register": {"*": {}}, }, }, { @@ -238,7 +239,7 @@ func Test_getTokenPermissions(t *testing.T) { InfraRole: apiv2.InfraRole_INFRA_ROLE_VIEWER.Enum(), }, want: tokenPermissions{ - "/metalstack.infra.v2.SwitchService/Get": {"*": entry{}}, + "/metalstack.infra.v2.SwitchService/Get": {"*": {}}, }, }, { @@ -259,8 +260,8 @@ func Test_getTokenPermissions(t *testing.T) { }, }, want: tokenPermissions{ - "/metalstack.api.v2.IPService/Create": {"a": entry{}}, - "/metalstack.api.v2.IPService/Delete": {"a": entry{}, "b": entry{}}, + "/metalstack.api.v2.IPService/Create": {"a": {}}, + "/metalstack.api.v2.IPService/Delete": {"a": {}, "b": {}}, }, }, { @@ -272,7 +273,7 @@ func Test_getTokenPermissions(t *testing.T) { }, }, want: tokenPermissions{ - "/metalstack.infra.v2.SwitchService/Register": {"*": entry{}}, + "/metalstack.infra.v2.SwitchService/Register": {"*": {}}, }, }, { @@ -294,15 +295,15 @@ func Test_getTokenPermissions(t *testing.T) { }, }, want: tokenPermissions{ - "/metalstack.api.v2.ProjectService/Create": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.TenantService/Get": {"b": entry{}, "a": entry{}, "c": entry{}}, - "/metalstack.api.v2.TenantService/Update": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.TenantService/Delete": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.TenantService/RemoveMember": {"c": entry{}}, - "/metalstack.api.v2.TenantService/UpdateMember": {"c": entry{}}, - "/metalstack.api.v2.TenantService/Invite": {"c": entry{}}, - "/metalstack.api.v2.TenantService/InviteDelete": {"c": entry{}}, - "/metalstack.api.v2.TenantService/InvitesList": {"c": entry{}}, + "/metalstack.api.v2.ProjectService/Create": {"b": {}, "c": {}}, + "/metalstack.api.v2.TenantService/Get": {"b": {}, "a": {}, "c": {}}, + "/metalstack.api.v2.TenantService/Update": {"b": {}, "c": {}}, + "/metalstack.api.v2.TenantService/Delete": {"b": {}, "c": {}}, + "/metalstack.api.v2.TenantService/RemoveMember": {"c": {}}, + "/metalstack.api.v2.TenantService/UpdateMember": {"c": {}}, + "/metalstack.api.v2.TenantService/Invite": {"c": {}}, + "/metalstack.api.v2.TenantService/InviteDelete": {"c": {}}, + "/metalstack.api.v2.TenantService/InvitesList": {"c": {}}, }, }, { @@ -319,45 +320,45 @@ func Test_getTokenPermissions(t *testing.T) { }, }, want: tokenPermissions{ - "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo": {"*": entry{}}, - "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/Get": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/List": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/Match": {"*": entry{}}, - "/metalstack.api.v2.HealthService/Get": {"*": entry{}}, - "/metalstack.api.v2.ImageService/Get": {"*": entry{}}, - "/metalstack.api.v2.ImageService/Latest": {"*": entry{}}, - "/metalstack.api.v2.ImageService/List": {"*": entry{}}, - "/metalstack.api.v2.MethodService/List": {"*": entry{}}, - "/metalstack.api.v2.MethodService/TokenScopedList": {"*": entry{}}, - "/metalstack.api.v2.PartitionService/Get": {"*": entry{}}, - "/metalstack.api.v2.PartitionService/List": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/Create": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.ProjectService/InviteAccept": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/InviteGet": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/List": {"*": entry{}}, - "/metalstack.api.v2.SizeService/Get": {"*": entry{}}, - "/metalstack.api.v2.SizeService/List": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Create": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Get": {"b": entry{}, "a": entry{}, "c": entry{}}, - "/metalstack.api.v2.TenantService/Update": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.TenantService/Delete": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.TenantService/RemoveMember": {"c": entry{}}, - "/metalstack.api.v2.TenantService/UpdateMember": {"c": entry{}}, - "/metalstack.api.v2.TenantService/Invite": {"c": entry{}}, - "/metalstack.api.v2.TenantService/InviteAccept": {"*": entry{}}, - "/metalstack.api.v2.TenantService/InviteDelete": {"c": entry{}}, - "/metalstack.api.v2.TenantService/InviteGet": {"*": entry{}}, - "/metalstack.api.v2.TenantService/InvitesList": {"c": entry{}}, - "/metalstack.api.v2.TenantService/List": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Create": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Get": {"*": entry{}}, - "/metalstack.api.v2.TokenService/List": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Refresh": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Revoke": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Update": {"*": entry{}}, - "/metalstack.api.v2.UserService/Get": {"*": entry{}}, - "/metalstack.api.v2.VersionService/Get": {"*": entry{}}, + "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo": {"*": {}}, + "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": {"*": {}}, + "/metalstack.api.v2.FilesystemService/Get": {"*": {}}, + "/metalstack.api.v2.FilesystemService/List": {"*": {}}, + "/metalstack.api.v2.FilesystemService/Match": {"*": {}}, + "/metalstack.api.v2.HealthService/Get": {"*": {}}, + "/metalstack.api.v2.ImageService/Get": {"*": {}}, + "/metalstack.api.v2.ImageService/Latest": {"*": {}}, + "/metalstack.api.v2.ImageService/List": {"*": {}}, + "/metalstack.api.v2.MethodService/List": {"*": {}}, + "/metalstack.api.v2.MethodService/TokenScopedList": {"*": {}}, + "/metalstack.api.v2.PartitionService/Get": {"*": {}}, + "/metalstack.api.v2.PartitionService/List": {"*": {}}, + "/metalstack.api.v2.ProjectService/Create": {"b": {}, "c": {}}, + "/metalstack.api.v2.ProjectService/InviteAccept": {"*": {}}, + "/metalstack.api.v2.ProjectService/InviteGet": {"*": {}}, + "/metalstack.api.v2.ProjectService/List": {"*": {}}, + "/metalstack.api.v2.SizeService/Get": {"*": {}}, + "/metalstack.api.v2.SizeService/List": {"*": {}}, + "/metalstack.api.v2.TenantService/Create": {"*": {}}, + "/metalstack.api.v2.TenantService/Get": {"b": {}, "a": {}, "c": {}}, + "/metalstack.api.v2.TenantService/Update": {"b": {}, "c": {}}, + "/metalstack.api.v2.TenantService/Delete": {"b": {}, "c": {}}, + "/metalstack.api.v2.TenantService/RemoveMember": {"c": {}}, + "/metalstack.api.v2.TenantService/UpdateMember": {"c": {}}, + "/metalstack.api.v2.TenantService/Invite": {"c": {}}, + "/metalstack.api.v2.TenantService/InviteAccept": {"*": {}}, + "/metalstack.api.v2.TenantService/InviteDelete": {"c": {}}, + "/metalstack.api.v2.TenantService/InviteGet": {"*": {}}, + "/metalstack.api.v2.TenantService/InvitesList": {"c": {}}, + "/metalstack.api.v2.TenantService/List": {"*": {}}, + "/metalstack.api.v2.TokenService/Create": {"*": {}}, + "/metalstack.api.v2.TokenService/Get": {"*": {}}, + "/metalstack.api.v2.TokenService/List": {"*": {}}, + "/metalstack.api.v2.TokenService/Refresh": {"*": {}}, + "/metalstack.api.v2.TokenService/Revoke": {"*": {}}, + "/metalstack.api.v2.TokenService/Update": {"*": {}}, + "/metalstack.api.v2.UserService/Get": {"*": {}}, + "/metalstack.api.v2.VersionService/Get": {"*": {}}, }, }, { @@ -379,31 +380,31 @@ func Test_getTokenPermissions(t *testing.T) { }, }, want: tokenPermissions{ - "/metalstack.api.v2.IPService/Get": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.IPService/Create": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.IPService/Update": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.IPService/List": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.IPService/Delete": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.MachineService/Get": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.MachineService/Create": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.MachineService/Update": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.MachineService/List": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.MachineService/Delete": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.NetworkService/Get": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.NetworkService/Create": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.NetworkService/Update": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.NetworkService/List": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.NetworkService/ListBaseNetworks": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.NetworkService/Delete": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.ProjectService/Get": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.ProjectService/Delete": {"c": entry{}}, - "/metalstack.api.v2.ProjectService/Update": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.ProjectService/RemoveMember": {"c": entry{}}, - "/metalstack.api.v2.ProjectService/UpdateMember": {"c": entry{}}, - "/metalstack.api.v2.ProjectService/Invite": {"c": entry{}}, - "/metalstack.api.v2.ProjectService/InviteDelete": {"c": entry{}}, - "/metalstack.api.v2.ProjectService/InvitesList": {"c": entry{}}, - "/metalstack.api.v2.ProjectService/Leave": {"a": entry{}}, + "/metalstack.api.v2.IPService/Get": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.IPService/Create": {"b": {}, "c": {}}, + "/metalstack.api.v2.IPService/Update": {"b": {}, "c": {}}, + "/metalstack.api.v2.IPService/List": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.IPService/Delete": {"b": {}, "c": {}}, + "/metalstack.api.v2.MachineService/Get": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.MachineService/Create": {"b": {}, "c": {}}, + "/metalstack.api.v2.MachineService/Update": {"b": {}, "c": {}}, + "/metalstack.api.v2.MachineService/List": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.MachineService/Delete": {"b": {}, "c": {}}, + "/metalstack.api.v2.NetworkService/Get": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.NetworkService/Create": {"b": {}, "c": {}}, + "/metalstack.api.v2.NetworkService/Update": {"b": {}, "c": {}}, + "/metalstack.api.v2.NetworkService/List": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.NetworkService/ListBaseNetworks": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.NetworkService/Delete": {"b": {}, "c": {}}, + "/metalstack.api.v2.ProjectService/Get": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.ProjectService/Delete": {"c": {}}, + "/metalstack.api.v2.ProjectService/Update": {"b": {}, "c": {}}, + "/metalstack.api.v2.ProjectService/RemoveMember": {"c": {}}, + "/metalstack.api.v2.ProjectService/UpdateMember": {"c": {}}, + "/metalstack.api.v2.ProjectService/Invite": {"c": {}}, + "/metalstack.api.v2.ProjectService/InviteDelete": {"c": {}}, + "/metalstack.api.v2.ProjectService/InvitesList": {"c": {}}, + "/metalstack.api.v2.ProjectService/Leave": {"a": {}}, }, }, { @@ -420,61 +421,61 @@ func Test_getTokenPermissions(t *testing.T) { }, }, want: tokenPermissions{ - "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo": {"*": entry{}}, - "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/Get": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/List": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/Match": {"*": entry{}}, - "/metalstack.api.v2.HealthService/Get": {"*": entry{}}, - "/metalstack.api.v2.IPService/Get": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.IPService/Create": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.IPService/Update": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.IPService/List": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.IPService/Delete": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.ImageService/Get": {"*": entry{}}, - "/metalstack.api.v2.ImageService/Latest": {"*": entry{}}, - "/metalstack.api.v2.ImageService/List": {"*": entry{}}, - "/metalstack.api.v2.MachineService/Get": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.MachineService/Create": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.MachineService/Update": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.MachineService/List": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.MachineService/Delete": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.MethodService/List": {"*": entry{}}, - "/metalstack.api.v2.MethodService/TokenScopedList": {"*": entry{}}, - "/metalstack.api.v2.NetworkService/Get": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.NetworkService/Create": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.NetworkService/Update": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.NetworkService/List": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.NetworkService/ListBaseNetworks": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.NetworkService/Delete": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.PartitionService/Get": {"*": entry{}}, - "/metalstack.api.v2.PartitionService/List": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/Get": {"a": entry{}, "b": entry{}, "c": entry{}}, - "/metalstack.api.v2.ProjectService/Delete": {"c": entry{}}, - "/metalstack.api.v2.ProjectService/Update": {"b": entry{}, "c": entry{}}, - "/metalstack.api.v2.ProjectService/RemoveMember": {"c": entry{}}, - "/metalstack.api.v2.ProjectService/UpdateMember": {"c": entry{}}, - "/metalstack.api.v2.ProjectService/Invite": {"c": entry{}}, - "/metalstack.api.v2.ProjectService/InviteAccept": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/InviteDelete": {"c": entry{}}, - "/metalstack.api.v2.ProjectService/InviteGet": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/InvitesList": {"c": entry{}}, - "/metalstack.api.v2.ProjectService/Leave": {"a": entry{}}, - "/metalstack.api.v2.ProjectService/List": {"*": entry{}}, - "/metalstack.api.v2.SizeService/Get": {"*": entry{}}, - "/metalstack.api.v2.SizeService/List": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Create": {"*": entry{}}, - "/metalstack.api.v2.TenantService/InviteAccept": {"*": entry{}}, - "/metalstack.api.v2.TenantService/InviteGet": {"*": entry{}}, - "/metalstack.api.v2.TenantService/List": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Create": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Get": {"*": entry{}}, - "/metalstack.api.v2.TokenService/List": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Refresh": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Revoke": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Update": {"*": entry{}}, - "/metalstack.api.v2.UserService/Get": {"*": entry{}}, - "/metalstack.api.v2.VersionService/Get": {"*": entry{}}, + "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo": {"*": {}}, + "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": {"*": {}}, + "/metalstack.api.v2.FilesystemService/Get": {"*": {}}, + "/metalstack.api.v2.FilesystemService/List": {"*": {}}, + "/metalstack.api.v2.FilesystemService/Match": {"*": {}}, + "/metalstack.api.v2.HealthService/Get": {"*": {}}, + "/metalstack.api.v2.IPService/Get": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.IPService/Create": {"b": {}, "c": {}}, + "/metalstack.api.v2.IPService/Update": {"b": {}, "c": {}}, + "/metalstack.api.v2.IPService/List": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.IPService/Delete": {"b": {}, "c": {}}, + "/metalstack.api.v2.ImageService/Get": {"*": {}}, + "/metalstack.api.v2.ImageService/Latest": {"*": {}}, + "/metalstack.api.v2.ImageService/List": {"*": {}}, + "/metalstack.api.v2.MachineService/Get": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.MachineService/Create": {"b": {}, "c": {}}, + "/metalstack.api.v2.MachineService/Update": {"b": {}, "c": {}}, + "/metalstack.api.v2.MachineService/List": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.MachineService/Delete": {"b": {}, "c": {}}, + "/metalstack.api.v2.MethodService/List": {"*": {}}, + "/metalstack.api.v2.MethodService/TokenScopedList": {"*": {}}, + "/metalstack.api.v2.NetworkService/Get": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.NetworkService/Create": {"b": {}, "c": {}}, + "/metalstack.api.v2.NetworkService/Update": {"b": {}, "c": {}}, + "/metalstack.api.v2.NetworkService/List": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.NetworkService/ListBaseNetworks": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.NetworkService/Delete": {"b": {}, "c": {}}, + "/metalstack.api.v2.PartitionService/Get": {"*": {}}, + "/metalstack.api.v2.PartitionService/List": {"*": {}}, + "/metalstack.api.v2.ProjectService/Get": {"a": {}, "b": {}, "c": {}}, + "/metalstack.api.v2.ProjectService/Delete": {"c": {}}, + "/metalstack.api.v2.ProjectService/Update": {"b": {}, "c": {}}, + "/metalstack.api.v2.ProjectService/RemoveMember": {"c": {}}, + "/metalstack.api.v2.ProjectService/UpdateMember": {"c": {}}, + "/metalstack.api.v2.ProjectService/Invite": {"c": {}}, + "/metalstack.api.v2.ProjectService/InviteAccept": {"*": {}}, + "/metalstack.api.v2.ProjectService/InviteDelete": {"c": {}}, + "/metalstack.api.v2.ProjectService/InviteGet": {"*": {}}, + "/metalstack.api.v2.ProjectService/InvitesList": {"c": {}}, + "/metalstack.api.v2.ProjectService/Leave": {"a": {}}, + "/metalstack.api.v2.ProjectService/List": {"*": {}}, + "/metalstack.api.v2.SizeService/Get": {"*": {}}, + "/metalstack.api.v2.SizeService/List": {"*": {}}, + "/metalstack.api.v2.TenantService/Create": {"*": {}}, + "/metalstack.api.v2.TenantService/InviteAccept": {"*": {}}, + "/metalstack.api.v2.TenantService/InviteGet": {"*": {}}, + "/metalstack.api.v2.TenantService/List": {"*": {}}, + "/metalstack.api.v2.TokenService/Create": {"*": {}}, + "/metalstack.api.v2.TokenService/Get": {"*": {}}, + "/metalstack.api.v2.TokenService/List": {"*": {}}, + "/metalstack.api.v2.TokenService/Refresh": {"*": {}}, + "/metalstack.api.v2.TokenService/Revoke": {"*": {}}, + "/metalstack.api.v2.TokenService/Update": {"*": {}}, + "/metalstack.api.v2.UserService/Get": {"*": {}}, + "/metalstack.api.v2.VersionService/Get": {"*": {}}, }, }, { @@ -489,45 +490,45 @@ func Test_getTokenPermissions(t *testing.T) { }, }, want: tokenPermissions{ - "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo": {"*": entry{}}, - "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/Get": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/List": {"*": entry{}}, - "/metalstack.api.v2.FilesystemService/Match": {"*": entry{}}, - "/metalstack.api.v2.HealthService/Get": {"*": entry{}}, - "/metalstack.api.v2.IPService/Get": {"a": entry{}}, - "/metalstack.api.v2.IPService/List": {"a": entry{}}, - "/metalstack.api.v2.ImageService/Get": {"*": entry{}}, - "/metalstack.api.v2.ImageService/Latest": {"*": entry{}}, - "/metalstack.api.v2.ImageService/List": {"*": entry{}}, - "/metalstack.api.v2.MachineService/Get": {"a": entry{}}, - "/metalstack.api.v2.MachineService/List": {"a": entry{}}, - "/metalstack.api.v2.MethodService/List": {"*": entry{}}, - "/metalstack.api.v2.MethodService/TokenScopedList": {"*": entry{}}, - "/metalstack.api.v2.NetworkService/Get": {"a": entry{}}, - "/metalstack.api.v2.NetworkService/List": {"a": entry{}}, - "/metalstack.api.v2.NetworkService/ListBaseNetworks": {"a": entry{}}, - "/metalstack.api.v2.PartitionService/Get": {"*": entry{}}, - "/metalstack.api.v2.PartitionService/List": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/Get": {"a": entry{}}, - "/metalstack.api.v2.ProjectService/InviteAccept": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/InviteGet": {"*": entry{}}, - "/metalstack.api.v2.ProjectService/Leave": {"a": entry{}}, - "/metalstack.api.v2.ProjectService/List": {"*": entry{}}, - "/metalstack.api.v2.SizeService/Get": {"*": entry{}}, - "/metalstack.api.v2.SizeService/List": {"*": entry{}}, - "/metalstack.api.v2.TenantService/Create": {"*": entry{}}, - "/metalstack.api.v2.TenantService/InviteAccept": {"*": entry{}}, - "/metalstack.api.v2.TenantService/InviteGet": {"*": entry{}}, - "/metalstack.api.v2.TenantService/List": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Create": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Get": {"*": entry{}}, - "/metalstack.api.v2.TokenService/List": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Refresh": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Revoke": {"*": entry{}}, - "/metalstack.api.v2.TokenService/Update": {"*": entry{}}, - "/metalstack.api.v2.UserService/Get": {"*": entry{}}, - "/metalstack.api.v2.VersionService/Get": {"*": entry{}}, + "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo": {"*": {}}, + "/grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo": {"*": {}}, + "/metalstack.api.v2.FilesystemService/Get": {"*": {}}, + "/metalstack.api.v2.FilesystemService/List": {"*": {}}, + "/metalstack.api.v2.FilesystemService/Match": {"*": {}}, + "/metalstack.api.v2.HealthService/Get": {"*": {}}, + "/metalstack.api.v2.IPService/Get": {"a": {}}, + "/metalstack.api.v2.IPService/List": {"a": {}}, + "/metalstack.api.v2.ImageService/Get": {"*": {}}, + "/metalstack.api.v2.ImageService/Latest": {"*": {}}, + "/metalstack.api.v2.ImageService/List": {"*": {}}, + "/metalstack.api.v2.MachineService/Get": {"a": {}}, + "/metalstack.api.v2.MachineService/List": {"a": {}}, + "/metalstack.api.v2.MethodService/List": {"*": {}}, + "/metalstack.api.v2.MethodService/TokenScopedList": {"*": {}}, + "/metalstack.api.v2.NetworkService/Get": {"a": {}}, + "/metalstack.api.v2.NetworkService/List": {"a": {}}, + "/metalstack.api.v2.NetworkService/ListBaseNetworks": {"a": {}}, + "/metalstack.api.v2.PartitionService/Get": {"*": {}}, + "/metalstack.api.v2.PartitionService/List": {"*": {}}, + "/metalstack.api.v2.ProjectService/Get": {"a": {}}, + "/metalstack.api.v2.ProjectService/InviteAccept": {"*": {}}, + "/metalstack.api.v2.ProjectService/InviteGet": {"*": {}}, + "/metalstack.api.v2.ProjectService/Leave": {"a": {}}, + "/metalstack.api.v2.ProjectService/List": {"*": {}}, + "/metalstack.api.v2.SizeService/Get": {"*": {}}, + "/metalstack.api.v2.SizeService/List": {"*": {}}, + "/metalstack.api.v2.TenantService/Create": {"*": {}}, + "/metalstack.api.v2.TenantService/InviteAccept": {"*": {}}, + "/metalstack.api.v2.TenantService/InviteGet": {"*": {}}, + "/metalstack.api.v2.TenantService/List": {"*": {}}, + "/metalstack.api.v2.TokenService/Create": {"*": {}}, + "/metalstack.api.v2.TokenService/Get": {"*": {}}, + "/metalstack.api.v2.TokenService/List": {"*": {}}, + "/metalstack.api.v2.TokenService/Refresh": {"*": {}}, + "/metalstack.api.v2.TokenService/Revoke": {"*": {}}, + "/metalstack.api.v2.TokenService/Update": {"*": {}}, + "/metalstack.api.v2.UserService/Get": {"*": {}}, + "/metalstack.api.v2.VersionService/Get": {"*": {}}, }, }, { @@ -553,7 +554,7 @@ func Test_getTokenPermissions(t *testing.T) { }, }, want: tokenPermissions{ - "/metalstack.api.v2.MachineService/Create": {"b": entry{}}, + "/metalstack.api.v2.MachineService/Create": {"b": {}}, }, }, { @@ -577,7 +578,7 @@ func Test_getTokenPermissions(t *testing.T) { }, }, want: tokenPermissions{ - "/metalstack.api.v2.ProjectService/Create": {"user-a": entry{}}, + "/metalstack.api.v2.ProjectService/Create": {"user-a": {}}, }, }, { @@ -605,7 +606,7 @@ func Test_getTokenPermissions(t *testing.T) { }, }, want: tokenPermissions{ - "/metalstack.api.v2.ProjectService/Create": {"user-a": entry{}}, + "/metalstack.api.v2.ProjectService/Create": {"user-a": {}}, }, }, { @@ -633,7 +634,7 @@ func Test_getTokenPermissions(t *testing.T) { }, }, want: tokenPermissions{ - "/metalstack.api.v2.MachineService/Create": {"project-a": entry{}}, + "/metalstack.api.v2.MachineService/Create": {"project-a": {}}, }, }, } diff --git a/pkg/service/vpn/admin/vpn-service.go b/pkg/service/vpn/admin/vpn-service.go new file mode 100644 index 00000000..ff56c0b7 --- /dev/null +++ b/pkg/service/vpn/admin/vpn-service.go @@ -0,0 +1,125 @@ +package admin + +import ( + "context" + "log/slog" + "time" + + headscalev1 "github.com/juanfont/headscale/gen/go/headscale/v1" + "google.golang.org/protobuf/types/known/timestamppb" + + adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" + "github.com/metal-stack/api/go/metalstack/admin/v2/adminv2connect" + "github.com/metal-stack/metal-apiserver/pkg/errorutil" + "github.com/metal-stack/metal-apiserver/pkg/repository" +) + +const defaultExpiration = time.Hour + +type Config struct { + Log *slog.Logger + Repo *repository.Store + headscaleClient headscalev1.HeadscaleServiceClient + headscaleAddress string +} + +type vpnService struct { + log *slog.Logger + repo *repository.Store + headscaleClient headscalev1.HeadscaleServiceClient + headscaleAddress string +} +type VPNService interface { + adminv2connect.VPNServiceHandler + CreateUser(context.Context, string) (*headscalev1.User, error) + UserExists(context.Context, string) (*headscalev1.User, bool) + ControlPlaneAddress() string + NodesConnected(context.Context) ([]*headscalev1.Node, error) + DeleteNode(ctx context.Context, machineID, projectID string) error +} + +func New(c Config) VPNService { + return &vpnService{ + log: c.Log, + repo: c.Repo, + headscaleClient: c.headscaleClient, + headscaleAddress: c.headscaleAddress, + } +} + +func (v *vpnService) Authkey(ctx context.Context, req *adminv2.VPNServiceAuthkeyRequest) (*adminv2.VPNServiceAuthkeyResponse, error) { + _, err := v.repo.Project(req.Project).Get(ctx, req.Project) + if err != nil { + return nil, err + } + + headscaleUser, ok := v.UserExists(ctx, req.Project) + if !ok { + user, err := v.CreateUser(ctx, req.Project) + if err != nil { + return nil, err + } + headscaleUser = user + } + + expiration := time.Now() + if req.Expires != nil { + expiration = expiration.Add(req.Expires.AsDuration()) + } else { + expiration = expiration.Add(defaultExpiration) + } + key, err := v.headscaleClient.CreatePreAuthKey(ctx, &headscalev1.CreatePreAuthKeyRequest{ + User: headscaleUser.Id, + Ephemeral: req.Ephemeral, + Expiration: timestamppb.New(expiration), + }) + if err != nil { + return nil, errorutil.Convert(err) + } + + return &adminv2.VPNServiceAuthkeyResponse{ + Address: v.headscaleAddress, + Authkey: key.PreAuthKey.Key, + }, nil +} + +func (v *vpnService) ControlPlaneAddress() string { + panic("unimplemented") +} + +func (v *vpnService) CreateUser(ctx context.Context, name string) (*headscalev1.User, error) { + resp, err := v.headscaleClient.CreateUser(ctx, &headscalev1.CreateUserRequest{ + Name: name, + }) + if err != nil { + return nil, err + } + return resp.User, nil +} + +func (v *vpnService) DeleteNode(ctx context.Context, machineID string, projectID string) error { + panic("unimplemented") +} + +func (v *vpnService) NodesConnected(context.Context) ([]*headscalev1.Node, error) { + panic("unimplemented") +} + +func (v *vpnService) UserExists(ctx context.Context, name string) (*headscalev1.User, bool) { + resp, err := v.headscaleClient.ListUsers(ctx, &headscalev1.ListUsersRequest{ + Name: name, + }) + if err != nil { + return nil, false + } + var headscaleUser *headscalev1.User + for _, user := range resp.Users { + if user.Name == name { + headscaleUser = user + } + } + if headscaleUser == nil { + return nil, false + } + return headscaleUser, true +} diff --git a/pkg/service/vpn/admin/vpn-service_test.go b/pkg/service/vpn/admin/vpn-service_test.go new file mode 100644 index 00000000..8095d03a --- /dev/null +++ b/pkg/service/vpn/admin/vpn-service_test.go @@ -0,0 +1,89 @@ +package admin + +import ( + "log/slog" + "os" + "testing" + "time" + + adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + + "github.com/metal-stack/metal-apiserver/pkg/test" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/durationpb" +) + +var ( + p0 = "00000000-0000-0000-0000-000000000000" +) + +func Test_vpnService_Authkey(t *testing.T) { + + t.Parallel() + + log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) + + testStore, repoCloser := test.StartRepositoryWithCleanup(t, log, test.WithCockroach(false)) + repo := testStore.Store + + headscaleClient, endpoint, headscaleCloser := test.StartHeadscale(t) + + defer func() { + repoCloser() + headscaleCloser() + }() + + test.CreateTenants(t, testStore, []*apiv2.TenantServiceCreateRequest{ + {Name: "john.doe@github"}, + }) + test.CreateProjects(t, repo, []*apiv2.ProjectServiceCreateRequest{ + { + Name: p0, + Description: "a description", + Login: "john.doe@github", + }, + }) + tests := []struct { + name string + req *adminv2.VPNServiceAuthkeyRequest + want *adminv2.VPNServiceAuthkeyResponse + wantErr error + }{ + + { + name: "create a new authkey", + req: &adminv2.VPNServiceAuthkeyRequest{ + Project: p0, + Ephemeral: false, + Expires: durationpb.New(time.Hour), + }, + want: &adminv2.VPNServiceAuthkeyResponse{ + Address: endpoint, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := &vpnService{ + log: log, + repo: testStore.Store, + headscaleClient: headscaleClient, + headscaleAddress: endpoint, + } + + got, gotErr := v.Authkey(t.Context(), tt.req) + if gotErr != nil { + if tt.wantErr == nil { + t.Errorf("Authkey() failed: %v", gotErr) + } + return + } + if tt.wantErr != nil { + t.Fatal("Authkey() succeeded unexpectedly") + } + require.Equal(t, tt.want.Address, got.Address) + require.Greater(t, len(got.Authkey), 10) + }) + } +} diff --git a/pkg/test/headscale-config.yaml b/pkg/test/headscale-config.yaml new file mode 100644 index 00000000..c1e09f74 --- /dev/null +++ b/pkg/test/headscale-config.yaml @@ -0,0 +1,106 @@ +--- +# headscale will look for a configuration file named `config.yaml` (or `config.json`) in the following order: +# +# - `/etc/headscale` +# - `~/.headscale` +# - current working directory + +# The url clients will connect to. +# Typically this will be a domain like: +# +# https://myheadscale.example.com:443 +# +server_url: http://127.0.0.1:8080 + +# Address to listen to / bind to on the server +# +# For production: +listen_addr: 0.0.0.0:8080 +# listen_addr: 127.0.0.1:8080 + +# Address to listen to /metrics and /debug, you may want +# to keep this endpoint private to your internal network +# metrics_listen_addr: 127.0.0.1:9090 + +# Address to listen for gRPC. +# gRPC is used for controlling a headscale server +# remotely with the CLI +# Note: Remote access _only_ works if you have +# valid certificates. +# +# For production: +grpc_listen_addr: 0.0.0.0:50443 +# grpc_listen_addr: 127.0.0.1:50443 + +# Allow the gRPC admin interface to run in INSECURE +# mode. This is not recommended as the traffic will +# be unencrypted. Only enable if you know what you +# are doing. +grpc_allow_insecure: true + +# The Noise section includes specific configuration for the +# TS2021 Noise protocol +noise: + # The Noise private key is used to encrypt the traffic between headscale and + # Tailscale clients when using the new Noise-based protocol. A missing key + # will be automatically generated. + private_key_path: /var/lib/headscale/noise_private.key + +# List of IP prefixes to allocate tailaddresses from. +# Each prefix consists of either an IPv4 or IPv6 address, +# and the associated prefix length, delimited by a slash. +# It must be within IP ranges supported by the Tailscale +# client - i.e., subnets of 100.64.0.0/10 and fd7a:115c:a1e0::/48. +# See below: +# IPv6: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#LL81C52-L81C71 +# IPv4: https://github.com/tailscale/tailscale/blob/22ebb25e833264f58d7c3f534a8b166894a89536/net/tsaddr/tsaddr.go#L33 +# Any other range is NOT supported, and it will cause unexpected issues. +prefixes: + v4: 100.64.0.0/10 + v6: fd7a:115c:a1e0::/48 + + # Strategy used for allocation of IPs to nodes, available options: + # - sequential (default): assigns the next free IP from the previous given + # IP. A best-effort approach is used and Headscale might leave holes in the + # IP range or fill up existing holes in the IP range. + # - random: assigns the next free IP from a pseudo-random IP generator (crypto/rand). + allocation: sequential + +# Disables the automatic check for headscale updates on startup +disable_check_updates: true + +# Time before an inactive ephemeral node is deleted? +ephemeral_node_inactivity_timeout: 30m + +log: + # Valid log levels: panic, fatal, error, warn, info, debug, trace + level: error + # Output formatting for logs: text or json + format: json + +database: + # Database type. Available options: sqlite, postgres + # Please note that using Postgres is highly discouraged as it is only supported for legacy reasons. + # All new development, testing and optimisations are done with SQLite in mind. + type: sqlite + + # Enable debug mode. This setting requires the log.level to be set to "debug" or "trace". + debug: true + log: + level: debug + + sqlite: + path: /var/lib/headscale/db.sqlite + write_ahead_log: false + +dns: + override_local_dns: false + magic_dns: false + +derp: + server: + # If enabled, runs the embedded DERP server and merges it into the rest of the DERP config + # The Headscale server_url defined above MUST be using https, DERP requires TLS to be in place + enabled: false + urls: + - https://controlplane.tailscale.com/derpmap/default \ No newline at end of file diff --git a/pkg/test/headscale.go b/pkg/test/headscale.go new file mode 100644 index 00000000..0b8a55c8 --- /dev/null +++ b/pkg/test/headscale.go @@ -0,0 +1,99 @@ +package test + +import ( + "context" + _ "embed" + "io" + "strings" + "testing" + "time" + + headscalev1 "github.com/juanfont/headscale/gen/go/headscale/v1" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/exec" + tlog "github.com/testcontainers/testcontainers-go/log" + "github.com/testcontainers/testcontainers-go/wait" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +//go:embed headscale-config.yaml +var headscaleConfig string + +func StartHeadscale(t testing.TB) (headscalev1.HeadscaleServiceClient, string, func()) { + ctx := t.Context() + + headscaleContainer, err := testcontainers.Run( + ctx, + "ghcr.io/juanfont/headscale:v0.27.1", + testcontainers.WithFiles(testcontainers.ContainerFile{ + Reader: strings.NewReader(headscaleConfig), + ContainerFilePath: "/config.yaml", + FileMode: 0o644, + }), + testcontainers.WithTmpfs(map[string]string{ + "/tmp": "rw", + "/var/lib/headscsale": "rw", + }), + testcontainers.WithExposedPorts("50443/tcp"), + testcontainers.WithWaitStrategy(wait.ForListeningPort("50443/tcp").WithStartupTimeout(time.Second*5)), + testcontainers.WithCmd("serve", "-c", "/config.yaml"), + testcontainers.WithLogger(tlog.TestLogger(t)), + ) + require.NoError(t, err) + + c, reader, err := headscaleContainer.Exec(ctx, []string{"headscale", "apikeys", "create"}, exec.Multiplexed()) + require.NoError(t, err) + assert.Zerof(t, c, "apikeys should have been created, expected return code 0, got %d", c) + + output, err := io.ReadAll(reader) + require.NoError(t, err) + apikey := strings.TrimSpace(string(output)) + t.Logf("apikey:%q\n", apikey) + require.NoError(t, err) + + endpoint, err = headscaleContainer.PortEndpoint(ctx, "50443/tcp", "") + require.NoError(t, err) + t.Log(endpoint) + + grpcOptions := []grpc.DialOption{ + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithPerRPCCredentials(tokenAuth{ + token: apikey, + }), + } + + conn, err := grpc.NewClient(endpoint, grpcOptions...) + require.NoError(t, err) + + client := headscalev1.NewHeadscaleServiceClient(conn) + + _, err = client.Health(ctx, &headscalev1.HealthRequest{}) + require.NoError(t, err) + + closer := func() { + _ = headscaleContainer.Terminate(ctx) + } + + return client, endpoint, closer +} + +type tokenAuth struct { + token string +} + +func (t tokenAuth) GetRequestMetadata( + ctx context.Context, + _ ...string, +) (map[string]string, error) { + return map[string]string{ + "authorization": "Bearer " + t.token, + }, nil +} + +func (tokenAuth) RequireTransportSecurity() bool { + return false +} From 7f34c2c770487143d2ddc3f2176181542825e58b Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Wed, 10 Dec 2025 09:42:17 +0100 Subject: [PATCH 02/18] Update api --- .../test/validation-interceptor_test.go | 2 +- go.mod | 43 ++++- go.sum | 113 +++++++++++- pkg/db/metal/machine.go | 7 +- pkg/db/queries/machine.go | 6 + pkg/db/queries/machine_test.go | 9 +- pkg/repository/machine.go | 18 ++ pkg/request/tokenpermissions_test.go | 2 + pkg/service/vpn/admin/vpn-service.go | 123 ++++++++++++- pkg/service/vpn/admin/vpn-service_test.go | 171 ++++++++++++++++++ 10 files changed, 470 insertions(+), 24 deletions(-) diff --git a/cmd/server/test/validation-interceptor_test.go b/cmd/server/test/validation-interceptor_test.go index f2c7cfbd..635006ca 100644 --- a/cmd/server/test/validation-interceptor_test.go +++ b/cmd/server/test/validation-interceptor_test.go @@ -38,7 +38,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa } _, err := apiv2connect.NewTokenServiceClient(srv.Client(), srv.URL).Create(t.Context(), req) require.Error(t, err) - require.EqualError(t, err, "invalid_argument: validation error:\n - description: must be shorter than 256 characters [string.is_description]") + require.EqualError(t, err, "invalid_argument: validation error: description: must be shorter than 256 characters") require.Equal(t, connect.CodeInvalidArgument, connect.CodeOf(err)) } diff --git a/go.mod b/go.mod index cb3b1a39..04ae339e 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/metal-stack/metal-apiserver go 1.25 require ( - buf.build/go/protovalidate v1.0.1 + buf.build/go/protovalidate v1.1.0 connectrpc.com/connect v1.19.1 connectrpc.com/grpchealth v1.4.0 connectrpc.com/grpcreflect v1.3.0 @@ -13,6 +13,7 @@ require ( github.com/alicebob/miniredis/v2 v2.35.0 github.com/avast/retry-go/v4 v4.7.0 github.com/cockroachdb/cockroach-go/v2 v2.4.3 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/golang-jwt/jwt/v5 v5.3.0 github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 @@ -25,7 +26,7 @@ require ( github.com/klauspost/connect-compress/v2 v2.1.0 github.com/lestrrat-go/jwx/v3 v3.0.12 github.com/markbates/goth v1.82.0 - github.com/metal-stack/api v0.0.36-0.20251210073043-abfdf6fa173a + github.com/metal-stack/api v0.0.36-0.20251212082837-bc1a1e478232 github.com/metal-stack/go-ipam v1.14.13 github.com/metal-stack/masterdata-api v0.13.0 github.com/metal-stack/metal-lib v0.23.5 @@ -50,7 +51,7 @@ require ( ) require ( - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20250912141014-52f32327d4b0.1 // indirect + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20251209175733-2a1774d88802.1 // indirect cel.dev/expr v0.25.1 // indirect dario.cat/mergo v1.0.2 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect @@ -69,20 +70,25 @@ require ( github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect - github.com/creack/pty v1.1.23 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/creachadair/mds v0.25.10 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/docker v28.5.2+incompatible // indirect github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/ebitengine/purego v0.9.1 // indirect github.com/emicklei/go-restful-openapi/v2 v2.11.0 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/glebarez/go-sqlite v1.22.0 // indirect + github.com/glebarez/sqlite v1.11.0 // indirect github.com/go-chi/chi/v5 v5.2.3 // indirect + github.com/go-gormigrate/gormigrate/v2 v2.1.5 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // indirect + github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect @@ -111,6 +117,12 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.6 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.2 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect @@ -123,6 +135,8 @@ require ( github.com/lopezator/migrator v0.3.1 // indirect github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect github.com/magiconair/properties v1.8.10 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mdelapenya/tlscert v0.2.0 // indirect github.com/minio/minlz v1.0.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect @@ -137,10 +151,12 @@ require ( github.com/montanaflynn/stats v0.7.1 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/ncruces/go-strftime v1.0.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect @@ -148,14 +164,22 @@ require ( github.com/prometheus/common v0.67.4 // indirect github.com/prometheus/otlptranslator v1.0.0 // indirect github.com/prometheus/procfs v0.19.2 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/rs/zerolog v1.34.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.12.0 // indirect github.com/segmentio/asm v1.2.1 // indirect github.com/shirou/gopsutil/v4 v4.25.11 // indirect github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect + github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/spf13/viper v1.21.0 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect github.com/stretchr/objx v0.5.3 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/tailscale/squibble v0.0.0-20251030164342-4d5df9caa993 // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect github.com/tklauser/numcpus v0.11.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect @@ -181,6 +205,7 @@ require ( go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect + go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect golang.org/x/net v0.47.0 // indirect @@ -192,5 +217,13 @@ require ( gopkg.in/cenkalti/backoff.v2 v2.2.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/postgres v1.6.0 // indirect + gorm.io/gorm v1.31.0 // indirect + modernc.org/libc v1.66.10 // indirect + modernc.org/mathutil v1.7.1 // indirect + modernc.org/memory v1.11.0 // indirect + modernc.org/sqlite v1.39.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect + tailscale.com v1.86.5 // indirect + zgo.at/zcache/v2 v2.4.1 // indirect ) diff --git a/go.sum b/go.sum index 7159fc09..10c47101 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20250912141014-52f32327d4b0.1 h1:31on4W/yPcV4nZHL4+UCiCvLPsMqe/vJcNg8Rci0scc= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20250912141014-52f32327d4b0.1/go.mod h1:fUl8CEN/6ZAMk6bP8ahBJPUJw7rbp+j4x+wCcYi2IG4= -buf.build/go/protovalidate v1.0.1 h1:Fwmf08OOUuKVeMvEnDmcKxQam4PJc/zFgvVX64BhTms= -buf.build/go/protovalidate v1.0.1/go.mod h1:SoZmvk/3ZzOVg9YSkTdm4grMAByjf8zgZq4ZNaLZXoQ= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20251209175733-2a1774d88802.1 h1:ZnX3qpF/pDiYrf+Q3p+/zCzZ5ELSpszy5hdVarDMSV4= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20251209175733-2a1774d88802.1/go.mod h1:fUl8CEN/6ZAMk6bP8ahBJPUJw7rbp+j4x+wCcYi2IG4= +buf.build/go/protovalidate v1.1.0 h1:pQqEQRpOo4SqS60qkvmhLTTQU9JwzEvdyiqAtXa5SeY= +buf.build/go/protovalidate v1.1.0/go.mod h1:bGZcPiAQDC3ErCHK3t74jSoJDFOs2JH3d7LWuTEIdss= cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14= @@ -66,12 +66,15 @@ github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNv github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= 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.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creachadair/mds v0.25.10 h1:9k9JB35D1xhOCFl0liBhagBBp8fWWkKZrA7UXsfoHtA= +github.com/creachadair/mds v0.25.10/go.mod h1:4hatI3hRM+qhzuAmqPRFvaBM8mONkS7nsLxkcuTYUIs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= @@ -91,6 +94,8 @@ github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pM 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= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +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= github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/emicklei/go-restful-openapi/v2 v2.11.0 h1:Ur+yGxoOH/7KRmcj/UoMFqC3VeNc9VOe+/XidumxTvk= @@ -103,10 +108,20 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= +github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= +github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= +github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-gormigrate/gormigrate/v2 v2.1.5 h1:1OyorA5LtdQw12cyJDEHuTrEV3GiXiIhS4/QTTa/SM8= +github.com/go-gormigrate/gormigrate/v2 v2.1.5/go.mod h1:mj9ekk/7CPF3VjopaFvWKN2v7fN3D9d3eEOAXRhi/+M= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I= +github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -170,6 +185,7 @@ github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9L github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -189,6 +205,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d h1:KJIErDwbSHjnp/SGzE5ed8Aol7JsKiI5X7yWKAtzhM0= +github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -224,6 +242,14 @@ github.com/jackc/pgtype v1.14.3 h1:h6W9cPuHsRWQFTWUZMAKMgG5jSwQI0Zurzdvlx3Plus= github.com/jackc/pgtype v1.14.3/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= +github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk= +github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -277,12 +303,19 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/goth v1.82.0 h1:8j/c34AjBSTNzO7zTsOyP5IYCQCMBTRBHAbBt/PI0bQ= github.com/markbates/goth v1.82.0/go.mod h1:/DRlcq0pyqkKToyZjsL2KgiA1zbF1HIjE7u2uC79rUk= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 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/metal-stack/api v0.0.36-0.20251210073043-abfdf6fa173a h1:bghLv594/MwdYVZXD54NRgiuTfCSOM7KNf0Q3eh5kR0= -github.com/metal-stack/api v0.0.36-0.20251210073043-abfdf6fa173a/go.mod h1:ksr+C/um5Q10t9FnC9UuQ1LvgH7Qsw1c0IwSbvWRfyE= +github.com/metal-stack/api v0.0.36-0.20251212082837-bc1a1e478232 h1:aOMJXkwTIsvnjeRyl/WaoEGla21+oFyRyIO0dwOgTHg= +github.com/metal-stack/api v0.0.36-0.20251212082837-bc1a1e478232/go.mod h1:4wrEGm7Qfm/PQ9zsl64A2T9efHYL/0b21+Wjla3TF+k= github.com/metal-stack/go-ipam v1.14.13 h1:/W5/MDBX5EU18xNDjlBvV6JjQ1Ot12dO2WxLvV6S8vc= github.com/metal-stack/go-ipam v1.14.13/go.mod h1:eif3UGUFP7CWJdrgLIOjhVM3G2K19GN8lhCgPVfvLDs= github.com/metal-stack/masterdata-api v0.13.0 h1:1AxnsiWiTMstjMsphZ0wMFT7aW3QQhAMumXnQ81PtHk= @@ -322,6 +355,8 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= +github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -336,6 +371,8 @@ github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgr github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -355,6 +392,8 @@ github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4 github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/redis/go-redis/v9 v9.17.2 h1:P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI= github.com/redis/go-redis/v9 v9.17.2/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= +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/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8= @@ -363,8 +402,13 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= +github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= @@ -374,8 +418,14 @@ github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1Tmu github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0= github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +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/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs= github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -395,6 +445,12 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33 h1:idh63uw+gsG05HwjZsAENCG4KZfyvjK03bpjxa5qRRk= +github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33/go.mod h1:EbW0wDK/qEUYI0A5bqq0C2kF8JTQwWONmGDBbzsxxHo= +github.com/tailscale/squibble v0.0.0-20251030164342-4d5df9caa993 h1:FyiiAvDAxpB0DrW2GW3KOVfi3YFOtsQUEeFWbf55JJU= +github.com/tailscale/squibble v0.0.0-20251030164342-4d5df9caa993/go.mod h1:xJkMmR3t+thnUQhA3Q4m2VSlS5pcOq+CIjmU/xfKKx4= github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU= github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY= github.com/testcontainers/testcontainers-go/modules/postgres v0.38.0 h1:KFdx9A0yF94K70T6ibSuvgkQQeX1xKlZVF3hEagXEtY= @@ -468,6 +524,8 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4hOxG5YpKCzkek= +go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -482,6 +540,8 @@ golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyy golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -513,7 +573,10 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -533,6 +596,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -570,7 +635,43 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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= +gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4= +gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo= +gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY= +gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= +modernc.org/cc/v4 v4.26.5 h1:xM3bX7Mve6G8K8b+T11ReenJOT+BmVqQj0FY5T4+5Y4= +modernc.org/cc/v4 v4.26.5/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.28.1 h1:wPKYn5EC/mYTqBO373jKjvX2n+3+aK7+sICCv4Fjy1A= +modernc.org/ccgo/v4 v4.28.1/go.mod h1:uD+4RnfrVgE6ec9NGguUNdhqzNIeeomeXf6CL0GTE5Q= +modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= +modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= +modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= +modernc.org/libc v1.66.10 h1:yZkb3YeLx4oynyR+iUsXsybsX4Ubx7MQlSYEw4yj59A= +modernc.org/libc v1.66.10/go.mod h1:8vGSEwvoUoltr4dlywvHqjtAqHBaw0j1jI7iFBTAr2I= +modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= +modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= +modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= +modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= +modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= +modernc.org/sqlite v1.39.1 h1:H+/wGFzuSCIEVCvXYVHX5RQglwhMOvtHSv+VtidL2r4= +modernc.org/sqlite v1.39.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE= +modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= +modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= +tailscale.com v1.86.5 h1:yBtWFjuLYDmxVnfnvPbZNZcKADCYgNfMd0rUAOA9XCs= +tailscale.com v1.86.5/go.mod h1:Lm8dnzU2i/Emw15r6sl3FRNp/liSQ/nYw6ZSQvIdZ1M= +zgo.at/zcache/v2 v2.4.1 h1:Dfjoi8yI0Uq7NCc4lo2kaQJJmp9Mijo21gef+oJstbY= +zgo.at/zcache/v2 v2.4.1/go.mod h1:gyCeoLVo01QjDZynjime8xUGHHMbsLiPyUTBpDGd4Gk= +zombiezen.com/go/postgrestest v1.0.1 h1:aXoADQAJmZDU3+xilYVut0pHhgc0sF8ZspPW9gFNwP4= +zombiezen.com/go/postgrestest v1.0.1/go.mod h1:marlZezr+k2oSJrvXHnZUs1olHqpE9czlz8ZYkVxliQ= diff --git a/pkg/db/metal/machine.go b/pkg/db/metal/machine.go index 01e3719d..b1773655 100644 --- a/pkg/db/metal/machine.go +++ b/pkg/db/metal/machine.go @@ -394,9 +394,10 @@ type BIOS struct { } type MachineVPN struct { - ControlPlaneAddress string `rethinkdb:"address"` - AuthKey string `rethinkdb:"auth_key"` - Connected bool `rethinkdb:"connected"` + ControlPlaneAddress string `rethinkdb:"address"` + AuthKey string `rethinkdb:"auth_key"` + Connected bool `rethinkdb:"connected"` + IPs []string `rethinkdb:"ips"` } // LEDState is the state of the LED of the Machine diff --git a/pkg/db/queries/machine.go b/pkg/db/queries/machine.go index 5f6cb206..2b1129a7 100644 --- a/pkg/db/queries/machine.go +++ b/pkg/db/queries/machine.go @@ -116,6 +116,12 @@ func MachineFilter(rq *apiv2.MachineQuery) func(q r.Term) r.Term { }) } } + // Only check if VPN is configured in this allocation + if alloc.Vpn != nil { + q = q.Filter(func(row r.Term) r.Term { + return row.Field("allocation").HasFields("vpn") + }) + } } if rq.Network != nil { diff --git a/pkg/db/queries/machine_test.go b/pkg/db/queries/machine_test.go index b79cb77c..bb774c3d 100644 --- a/pkg/db/queries/machine_test.go +++ b/pkg/db/queries/machine_test.go @@ -50,7 +50,6 @@ var ( ConsolePassword: "", Succeeded: true, Role: metal.RoleMachine, - VPN: &metal.MachineVPN{}, UUID: "alloc-m1", FirewallRules: &metal.FirewallRules{ Egress: []metal.EgressRule{}, @@ -131,7 +130,7 @@ var ( ConsolePassword: "", Succeeded: true, Role: metal.RoleFirewall, - VPN: &metal.MachineVPN{}, + VPN: &metal.MachineVPN{ControlPlaneAddress: "https://headscale.metal-stack.io", IPs: []string{}}, UUID: "alloc-m2", FirewallRules: &metal.FirewallRules{ Egress: []metal.EgressRule{}, @@ -200,7 +199,6 @@ var ( ConsolePassword: "", Succeeded: false, Role: "", - VPN: &metal.MachineVPN{}, UUID: "", FirewallRules: &metal.FirewallRules{ Egress: []metal.EgressRule{}, @@ -388,6 +386,11 @@ func TestMachineFilter(t *testing.T) { rq: &apiv2.MachineQuery{Allocation: &apiv2.MachineAllocationQuery{Labels: &apiv2.Labels{Labels: map[string]string{"color": "red"}}}}, want: []*metal.Machine{m1}, }, + { + name: "by allocation vpn", + rq: &apiv2.MachineQuery{Allocation: &apiv2.MachineAllocationQuery{Vpn: &apiv2.MachineVPN{}}}, + want: []*metal.Machine{m2}, + }, // Network Queries { name: "by network id", diff --git a/pkg/repository/machine.go b/pkg/repository/machine.go index 6d1d2285..f55b362c 100644 --- a/pkg/repository/machine.go +++ b/pkg/repository/machine.go @@ -24,6 +24,23 @@ type ( } ) +func (r *machineRepository) SetMachineConnectedToVPN(ctx context.Context, id string, connected bool, ips []string) error { + m, err := r.get(ctx, id) + if err != nil { + return err + } + if m.Allocation == nil { + return errorutil.InvalidArgument("machine is not allocated") + } + if m.Allocation.VPN == nil { + return errorutil.InvalidArgument("machine is not configured for VPN") + } + m.Allocation.VPN.Connected = connected + m.Allocation.VPN.IPs = ips + + return r.s.ds.Machine().Update(ctx, m) +} + func (r *machineRepository) get(ctx context.Context, id string) (*metal.Machine, error) { machine, err := r.s.ds.Machine().Get(ctx, id) if err != nil { @@ -228,6 +245,7 @@ func (r *machineRepository) convertToProto(ctx context.Context, m *metal.Machine ControlPlaneAddress: alloc.VPN.ControlPlaneAddress, AuthKey: alloc.VPN.AuthKey, Connected: alloc.VPN.Connected, + Ips: alloc.VPN.IPs, } } for _, dns := range alloc.DNSServers { diff --git a/pkg/request/tokenpermissions_test.go b/pkg/request/tokenpermissions_test.go index 9a144238..42fa6672 100644 --- a/pkg/request/tokenpermissions_test.go +++ b/pkg/request/tokenpermissions_test.go @@ -145,6 +145,7 @@ func Test_getTokenPermissions(t *testing.T) { "/metalstack.api.v2.TokenService/Update": {"*": {}}, "/metalstack.api.v2.UserService/Get": {"*": {}}, "/metalstack.api.v2.VersionService/Get": {"*": {}}, + "/metalstack.infra.v2.EventService/Send": {"*": {}}, "/metalstack.infra.v2.BMCService/UpdateBMCInfo": {"*": {}}, "/metalstack.infra.v2.SwitchService/Get": {"*": {}}, "/metalstack.infra.v2.SwitchService/Heartbeat": {"*": {}}, @@ -225,6 +226,7 @@ func Test_getTokenPermissions(t *testing.T) { InfraRole: apiv2.InfraRole_INFRA_ROLE_EDITOR.Enum(), }, want: tokenPermissions{ + "/metalstack.infra.v2.EventService/Send": {"*": {}}, "/metalstack.infra.v2.BMCService/UpdateBMCInfo": {"*": {}}, "/metalstack.infra.v2.SwitchService/Get": {"*": {}}, "/metalstack.infra.v2.SwitchService/Heartbeat": {"*": {}}, diff --git a/pkg/service/vpn/admin/vpn-service.go b/pkg/service/vpn/admin/vpn-service.go index ff56c0b7..eb1a4956 100644 --- a/pkg/service/vpn/admin/vpn-service.go +++ b/pkg/service/vpn/admin/vpn-service.go @@ -2,16 +2,23 @@ package admin import ( "context" + "errors" + "fmt" "log/slog" + "slices" + "strings" "time" headscalev1 "github.com/juanfont/headscale/gen/go/headscale/v1" + headscaledb "github.com/juanfont/headscale/hscontrol/db" "google.golang.org/protobuf/types/known/timestamppb" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" "github.com/metal-stack/api/go/metalstack/admin/v2/adminv2connect" + apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/metal-stack/metal-apiserver/pkg/errorutil" "github.com/metal-stack/metal-apiserver/pkg/repository" + "github.com/metal-stack/metal-lib/pkg/pointer" ) const defaultExpiration = time.Hour @@ -36,6 +43,7 @@ type VPNService interface { ControlPlaneAddress() string NodesConnected(context.Context) ([]*headscalev1.Node, error) DeleteNode(ctx context.Context, machineID, projectID string) error + EvaluateVPNConnected(ctx context.Context) error } func New(c Config) VPNService { @@ -84,25 +92,43 @@ func (v *vpnService) Authkey(ctx context.Context, req *adminv2.VPNServiceAuthkey } func (v *vpnService) ControlPlaneAddress() string { - panic("unimplemented") + return v.headscaleAddress } func (v *vpnService) CreateUser(ctx context.Context, name string) (*headscalev1.User, error) { resp, err := v.headscaleClient.CreateUser(ctx, &headscalev1.CreateUserRequest{ Name: name, }) - if err != nil { - return nil, err + // TODO check if this is still like this + if err != nil && !strings.Contains(err.Error(), headscaledb.ErrUserExists.Error()) { + return nil, fmt.Errorf("failed to create new VPN user: %w", err) } return resp.User, nil } func (v *vpnService) DeleteNode(ctx context.Context, machineID string, projectID string) error { - panic("unimplemented") + machine, err := v.getNode(ctx, machineID, projectID) + if err != nil || machine == nil { + return err + } + + req := &headscalev1.DeleteNodeRequest{ + NodeId: machine.Id, + } + if _, err := v.headscaleClient.DeleteNode(ctx, req); err != nil { + return fmt.Errorf("failed to delete machine: %w", err) + } + + return nil } -func (v *vpnService) NodesConnected(context.Context) ([]*headscalev1.Node, error) { - panic("unimplemented") +func (v *vpnService) NodesConnected(ctx context.Context) ([]*headscalev1.Node, error) { + resp, err := v.headscaleClient.ListNodes(ctx, &headscalev1.ListNodesRequest{}) + if err != nil || resp == nil { + return nil, fmt.Errorf("failed to list machines: %w", err) + } + + return resp.Nodes, nil } func (v *vpnService) UserExists(ctx context.Context, name string) (*headscalev1.User, bool) { @@ -123,3 +149,88 @@ func (v *vpnService) UserExists(ctx context.Context, name string) (*headscalev1. } return headscaleUser, true } + +func (v *vpnService) getNode(ctx context.Context, machineID, projectID string) (machine *headscalev1.Node, err error) { + req := &headscalev1.ListNodesRequest{ + User: projectID, + } + resp, err := v.headscaleClient.ListNodes(ctx, req) + if err != nil || resp == nil { + return nil, fmt.Errorf("failed to list nodes: %w", err) + } + + for _, m := range resp.Nodes { + if m.Name == machineID { + return m, nil + } + } + + return nil, nil +} + +func (v *vpnService) EvaluateVPNConnected(ctx context.Context) error { + ms, err := v.repo.UnscopedMachine().List(ctx, &apiv2.MachineQuery{ + Allocation: &apiv2.MachineAllocationQuery{ + // Return only allocation machines which have a vpn configured + Vpn: &apiv2.MachineVPN{}, + }, + }) + if err != nil { + return err + } + + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) + defer cancel() + + headscaleNodes, err := v.NodesConnected(ctx) + if err != nil { + return err + } + + var errs []error + for _, m := range ms { + m := m + if m.Allocation == nil || m.Allocation.Vpn == nil { + continue + } + + index := slices.IndexFunc(headscaleNodes, func(hm *headscalev1.Node) bool { + if hm.Name != m.Uuid { + return false + } + + if pointer.SafeDeref(hm.User).Name != m.Allocation.Project { + return false + } + + return true + }) + + if index < 0 { + continue + } + + connected := headscaleNodes[index].Online + ips := headscaleNodes[index].IpAddresses + + if m.Allocation.Vpn.Connected == connected && slices.Equal(m.Allocation.Vpn.Ips, ips) { + v.log.Info("not updating vpn because already up-to-date", "machine", m.Uuid, "connected", connected, "ips", ips) + continue + } + + err = v.repo.UnscopedMachine().AdditionalMethods().SetMachineConnectedToVPN(ctx, m.Uuid, connected, ips) + if err != nil { + errs = append(errs, err) + v.log.Error("unable to update vpn connected state, continue anyway", "machine", m.Uuid, "error", err) + continue + } + + v.log.Info("updated vpn connected state", "machine", m.Uuid, "connected", connected, "ips", ips) + } + + if len(errs) > 0 { + return fmt.Errorf("errors occurred when evaluating machine vpn connections:%w", errors.Join(errs...)) + } + + return nil +} diff --git a/pkg/service/vpn/admin/vpn-service_test.go b/pkg/service/vpn/admin/vpn-service_test.go index 8095d03a..682c0ac5 100644 --- a/pkg/service/vpn/admin/vpn-service_test.go +++ b/pkg/service/vpn/admin/vpn-service_test.go @@ -1,13 +1,17 @@ package admin import ( + "context" "log/slog" "os" "testing" "time" + "github.com/davecgh/go-spew/spew" + v1 "github.com/juanfont/headscale/gen/go/headscale/v1" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + "github.com/metal-stack/metal-lib/pkg/pointer" "github.com/metal-stack/metal-apiserver/pkg/test" "github.com/stretchr/testify/require" @@ -87,3 +91,170 @@ func Test_vpnService_Authkey(t *testing.T) { }) } } + +func Test_vpnService_DeleteNode(t *testing.T) { + t.Skip() + + log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) + ctx := t.Context() + headscaleClient, endpoint, headscaleCloser := test.StartHeadscale(t) + + user, err := headscaleClient.CreateUser(ctx, &v1.CreateUserRequest{ + Name: "p1", + }) + require.NoError(t, err) + + key, err := headscaleClient.CreatePreAuthKey(ctx, &v1.CreatePreAuthKeyRequest{ + User: user.User.Id, + }) + require.NoError(t, err) + spew.Dump(key) + + node, err := headscaleClient.RegisterNode(ctx, &v1.RegisterNodeRequest{ + User: "p1", + Key: key.String(), + }) + require.NoError(t, err) + + defer func() { + headscaleCloser() + }() + + tests := []struct { + name string + machineID string + projectID string + wantErr bool + }{ + { + name: "delete existing node", + machineID: node.Node.Name, + projectID: "p1", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := &vpnService{ + log: log, + headscaleClient: headscaleClient, + headscaleAddress: endpoint, + } + + gotErr := v.DeleteNode(ctx, tt.machineID, tt.projectID) + if gotErr != nil { + if !tt.wantErr { + t.Errorf("DeleteNode() failed: %v", gotErr) + } + return + } + if tt.wantErr { + t.Fatal("DeleteNode() succeeded unexpectedly") + } + }) + } +} + +func Test_vpnService_CreateUser(t *testing.T) { + + log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) + ctx := t.Context() + headscaleClient, _, headscaleCloser := test.StartHeadscale(t) + defer headscaleCloser() + + _, err := headscaleClient.CreateUser(ctx, &v1.CreateUserRequest{ + Name: "p1", + }) + require.NoError(t, err) + + tests := []struct { + name string + username string + want *string + wantErr bool + }{ + { + name: "create new user", + username: "p2", + want: pointer.Pointer("p2"), + }, + { + name: "create existing user", + username: "p1", + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := &vpnService{ + log: log, + headscaleClient: headscaleClient, + } + got, gotErr := v.CreateUser(t.Context(), tt.username) + if gotErr != nil { + if !tt.wantErr { + t.Errorf("CreateUser() failed: %v", gotErr) + } + return + } + if tt.wantErr { + t.Fatal("CreateUser() succeeded unexpectedly") + } + if got.Name != *tt.want { + t.Errorf("CreateUser() got:%s want:%s", got.Name, *tt.want) + } + }) + } +} + +func Test_vpnService_UserExists(t *testing.T) { + + log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) + ctx := t.Context() + headscaleClient, _, headscaleCloser := test.StartHeadscale(t) + defer headscaleCloser() + + _, err := headscaleClient.CreateUser(ctx, &v1.CreateUserRequest{ + Name: "p1", + }) + require.NoError(t, err) + + tests := []struct { + name string + username string + want *string + want2 bool + }{ + { + name: "get existing user", + username: "p1", + want: pointer.Pointer("p1"), + want2: true, + }, + { + name: "get non existing user", + username: "p2", + want: nil, + want2: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := &vpnService{ + log: log, + headscaleClient: headscaleClient, + } + got, got2 := v.UserExists(context.Background(), tt.username) + if got2 != tt.want2 { + t.Errorf("UserExists() = %v, want %v", got2, tt.want2) + } + if !got2 { + return + } + if got.Name != *tt.want { + t.Errorf("UserExists() got:%s want:%s", got.Name, *tt.want) + } + }) + } +} From fb3e89477f237adf16672513b156204aebe5c2eb Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sat, 13 Dec 2025 09:14:51 +0100 Subject: [PATCH 03/18] add vpn connected machines and wire up in services --- cmd/server/main.go | 27 +++++++++ cmd/server/serve-cmd.go | 58 ++++++++++++++++++ cmd/server/server_test.go | 2 +- cmd/server/vpn-cmd.go | 73 +++++++++++++++++++++++ go.mod | 2 +- go.sum | 2 + pkg/service/services.go | 15 +++++ pkg/service/vpn/admin/vpn-service.go | 28 ++++----- pkg/service/vpn/admin/vpn-service_test.go | 14 ++--- 9 files changed, 198 insertions(+), 23 deletions(-) create mode 100644 cmd/server/vpn-cmd.go diff --git a/cmd/server/main.go b/cmd/server/main.go index 461ca509..41637d67 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -217,6 +217,32 @@ var ( Value: "metal-stack", Usage: "ensures a provider tenant on startup (used for bootstrapping and technical tokens). can be disabled by setting to empty string.", } + // Headscale + headscaleAddressFlag = &cli.StringFlag{ + Name: "headscale-addr", + Value: "headscale:50443", + Usage: "address of headscale grpc server endpoint", + EnvVars: []string{"HEADSCALE_ADDRESS"}, + } + headscaleControlplaneAddressFlag = &cli.StringFlag{ + Name: "headscale-cp-addr", + Value: "", + Usage: "controlplane address of headscale server reachable from the nodes to join", + EnvVars: []string{"HEADSCALE_CONTROLPLANE_ADDRESS"}, + } + headscaleApikeyFlag = &cli.StringFlag{ + Name: "headscale-api-key", + Value: "", + Usage: "initial api key to connect to the headscale grpc server", + EnvVars: []string{"HEADSCALE_API_KEY"}, + } + headscaleEnabledFlag = &cli.BoolFlag{ + Name: "headscale-enabled", + Value: false, + Usage: "toggle if headscale should be enabled", + EnvVars: []string{"HEADSCALE_ENABLED"}, + } + // End Headscale ) func main() { @@ -227,6 +253,7 @@ func main() { newServeCmd(), newTokenCmd(), newDatastoreCmd(), + newVPNCmd(), }, } diff --git a/cmd/server/serve-cmd.go b/cmd/server/serve-cmd.go index 87f9e6d9..de9e7a8d 100644 --- a/cmd/server/serve-cmd.go +++ b/cmd/server/serve-cmd.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "log/slog" "net/http" @@ -12,8 +13,12 @@ import ( "github.com/alicebob/miniredis/v2" "github.com/avast/retry-go/v4" compress "github.com/klauspost/connect-compress/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" "gopkg.in/rethinkdb/rethinkdb-go.v6" + headscalev1 "github.com/juanfont/headscale/gen/go/headscale/v1" + ipamv1 "github.com/metal-stack/go-ipam/api/v1" ipamv1connect "github.com/metal-stack/go-ipam/api/v1/apiv1connect" mdm "github.com/metal-stack/masterdata-api/pkg/client" @@ -70,6 +75,10 @@ func newServeCmd() *cli.Command { oidcEndSessionUrlFlag, oidcUniqueUserKeyFlag, oidcTLSSkipVerifyFlag, + headscaleAddressFlag, + headscaleControlplaneAddressFlag, + headscaleApikeyFlag, + headscaleEnabledFlag, }, Action: func(ctx *cli.Context) error { log, err := createLogger(ctx) @@ -97,6 +106,11 @@ func newServeCmd() *cli.Command { return fmt.Errorf("unable to create masterdata.client: %w", err) } + hc, err := createHeadscaleClient(ctx, log) + if err != nil { + return err + } + connectOpts := rethinkdb.ConnectOpts{ Addresses: ctx.StringSlice(rethinkdbAddressesFlag.Name), Database: ctx.String(rethinkdbDBNameFlag.Name), @@ -140,6 +154,8 @@ func newServeCmd() *cli.Command { OIDCUniqueUserKey: ctx.String(oidcUniqueUserKeyFlag.Name), OIDCTLSSkipVerify: ctx.Bool(oidcTLSSkipVerifyFlag.Name), IsStageDev: strings.EqualFold(stage, stageDEV), + HeadscaleControlplaneAddress: ctx.String(headscaleControlplaneAddressFlag.Name), + HeadscaleClient: hc, } if providerTenant := ctx.String(ensureProviderTenantFlag.Name); providerTenant != "" { @@ -334,3 +350,45 @@ func createIpamClient(cli *cli.Context, log *slog.Logger) (ipamv1connect.IpamSer log.Info("ipam initialized") return ipamService, nil } + +func createHeadscaleClient(cli *cli.Context, log *slog.Logger) (headscalev1.HeadscaleServiceClient, error) { + if !cli.Bool(headscaleEnabledFlag.Name) { + log.Info("headscale is not enabled, not configuring vpn services") + return nil, nil + } + + apikey := cli.String(headscaleApikeyFlag.Name) + endpoint := cli.String(headscaleAddressFlag.Name) + + grpcOptions := []grpc.DialOption{ + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithPerRPCCredentials(tokenAuth{ + token: apikey, + }), + } + + conn, err := grpc.NewClient(endpoint, grpcOptions...) + if err != nil { + return nil, fmt.Errorf("unable to create grpc client:%w", err) + } + client := headscalev1.NewHeadscaleServiceClient(conn) + + return client, nil +} + +type tokenAuth struct { + token string +} + +func (t tokenAuth) GetRequestMetadata( + ctx context.Context, + _ ...string, +) (map[string]string, error) { + return map[string]string{ + "authorization": "Bearer " + t.token, + }, nil +} + +func (tokenAuth) RequireTransportSecurity() bool { + return false +} diff --git a/cmd/server/server_test.go b/cmd/server/server_test.go index 6a28ce5b..3f7fb64c 100644 --- a/cmd/server/server_test.go +++ b/cmd/server/server_test.go @@ -15,7 +15,7 @@ func Test_newServeCmd(t *testing.T) { args := []string{"-h"} cmd := newServeCmd() - require.Len(t, cmd.Flags, 37) + require.Len(t, cmd.Flags, 41) app.Commands = []*cli.Command{cmd} err := app.Run(args) diff --git a/cmd/server/vpn-cmd.go b/cmd/server/vpn-cmd.go new file mode 100644 index 00000000..8730a982 --- /dev/null +++ b/cmd/server/vpn-cmd.go @@ -0,0 +1,73 @@ +package main + +import ( + "fmt" + + "github.com/metal-stack/metal-apiserver/pkg/db/generic" + "github.com/metal-stack/metal-apiserver/pkg/repository" + vpnadmin "github.com/metal-stack/metal-apiserver/pkg/service/vpn/admin" + "github.com/urfave/cli/v2" + "gopkg.in/rethinkdb/rethinkdb-go.v6" +) + +func newVPNCmd() *cli.Command { + return &cli.Command{ + Name: "vpn", + Flags: []cli.Flag{ + rethinkdbAddressesFlag, + rethinkdbDBNameFlag, + rethinkdbPasswordFlag, + rethinkdbUserFlag, + headscaleAddressFlag, + headscaleApikeyFlag, + headscaleEnabledFlag, + }, + Subcommands: []*cli.Command{ + { + Name: "connected-machines", + Description: "evaluates whether machines connected to vpn and detects their vpn ip addresses", + Action: func(ctx *cli.Context) error { + log, err := createLogger(ctx) + if err != nil { + return fmt.Errorf("unable to create logger %w", err) + } + + hc, err := createHeadscaleClient(ctx, log) + if err != nil { + return err + } + if hc == nil || !ctx.Bool(headscaleEnabledFlag.Name) { + log.Info("headscale is disabled, not checking for connected machines") + } + + connectOpts := rethinkdb.ConnectOpts{ + Addresses: ctx.StringSlice(rethinkdbAddressesFlag.Name), + Database: ctx.String(rethinkdbDBNameFlag.Name), + Username: ctx.String(rethinkdbUserFlag.Name), + Password: ctx.String(rethinkdbPasswordFlag.Name), + MaxIdle: 10, + MaxOpen: 20, + } + + ds, err := generic.New(log.WithGroup("datastore"), connectOpts) + if err != nil { + return fmt.Errorf("unable to create datastore: %w", err) + } + + repo, err := repository.New(log, nil, ds, nil, nil) + if err != nil { + return fmt.Errorf("unable to create repository: %w", err) + } + + vpnService := vpnadmin.New(vpnadmin.Config{ + Log: log, + Repo: repo, + HeadscaleClient: hc, + }) + + return vpnService.EvaluateVPNConnected(ctx.Context) + }, + }, + }, + } +} diff --git a/go.mod b/go.mod index 7a785165..2a81dafb 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/samber/lo v1.52.0 github.com/stretchr/testify v1.11.1 github.com/testcontainers/testcontainers-go v0.40.0 - github.com/testcontainers/testcontainers-go/modules/postgres v0.38.0 + github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 github.com/testcontainers/testcontainers-go/modules/valkey v0.40.0 github.com/urfave/cli/v2 v2.27.7 go.opentelemetry.io/otel/exporters/prometheus v0.60.0 diff --git a/go.sum b/go.sum index 3607ae9f..79ea80f4 100644 --- a/go.sum +++ b/go.sum @@ -453,6 +453,8 @@ github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+ github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY= github.com/testcontainers/testcontainers-go/modules/postgres v0.38.0 h1:KFdx9A0yF94K70T6ibSuvgkQQeX1xKlZVF3hEagXEtY= github.com/testcontainers/testcontainers-go/modules/postgres v0.38.0/go.mod h1:T/QRECND6N6tAKMxF1Za+G2tpwnGEHcODzHRsgIpw9M= +github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 h1:s2bIayFXlbDFexo96y+htn7FzuhpXLYJNnIuglNKqOk= +github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0/go.mod h1:h+u/2KoREGTnTl9UwrQ/g+XhasAT8E6dClclAADeXoQ= github.com/testcontainers/testcontainers-go/modules/valkey v0.40.0 h1:V0zwJVnN8fOT++ySwo/P5cwd3pmXI7O4VdA7kQ+5OiM= github.com/testcontainers/testcontainers-go/modules/valkey v0.40.0/go.mod h1:z+ndszow9abHiSnpO/hOvCgUMv80FldiKZHSpMwd80s= github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= diff --git a/pkg/service/services.go b/pkg/service/services.go index fefc6ec8..e375371f 100644 --- a/pkg/service/services.go +++ b/pkg/service/services.go @@ -13,10 +13,13 @@ import ( "connectrpc.com/grpcreflect" "connectrpc.com/otelconnect" "connectrpc.com/validate" + + headscalev1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/metal-stack/api/go/metalstack/admin/v2/adminv2connect" "github.com/metal-stack/api/go/metalstack/api/v2/apiv2connect" "github.com/metal-stack/api/go/metalstack/infra/v2/infrav2connect" "github.com/metal-stack/api/go/permissions" + ipamv1connect "github.com/metal-stack/go-ipam/api/v1/apiv1connect" mdm "github.com/metal-stack/masterdata-api/pkg/client" authpkg "github.com/metal-stack/metal-apiserver/pkg/auth" @@ -52,6 +55,7 @@ import ( "github.com/metal-stack/metal-apiserver/pkg/service/token" tokenadmin "github.com/metal-stack/metal-apiserver/pkg/service/token/admin" "github.com/metal-stack/metal-apiserver/pkg/service/version" + vpnadmin "github.com/metal-stack/metal-apiserver/pkg/service/vpn/admin" tokencommon "github.com/metal-stack/metal-apiserver/pkg/token" "github.com/metal-stack/metal-lib/auditing" "github.com/redis/go-redis/v9" @@ -82,6 +86,8 @@ type Config struct { MaxRequestsPerMinuteToken int MaxRequestsPerMinuteUnauthenticated int IsStageDev bool + HeadscaleControlplaneAddress string + HeadscaleClient headscalev1.HeadscaleServiceClient } type RedisConfig struct { @@ -248,6 +254,15 @@ func New(log *slog.Logger, c Config) (*http.ServeMux, error) { mux.Handle(adminv2connect.NewSwitchServiceHandler(adminSwitchService, adminInterceptors)) mux.Handle(adminv2connect.NewMachineServiceHandler(adminMachineService, adminInterceptors)) mux.Handle(adminv2connect.NewTokenServiceHandler(adminTokenService, adminInterceptors)) + if c.HeadscaleClient != nil { + adminVPNService := vpnadmin.New(vpnadmin.Config{ + Log: log, + Repo: c.Repository, + HeadscaleClient: c.HeadscaleClient, + HeadscaleControlplaneAddress: c.HeadscaleControlplaneAddress, + }) + mux.Handle(adminv2connect.NewVPNServiceHandler(adminVPNService)) + } // Infra services infraSwitchService := switchinfra.New(switchinfra.Config{Log: log, Repo: c.Repository}) diff --git a/pkg/service/vpn/admin/vpn-service.go b/pkg/service/vpn/admin/vpn-service.go index eb1a4956..fcb97ed6 100644 --- a/pkg/service/vpn/admin/vpn-service.go +++ b/pkg/service/vpn/admin/vpn-service.go @@ -24,17 +24,17 @@ import ( const defaultExpiration = time.Hour type Config struct { - Log *slog.Logger - Repo *repository.Store - headscaleClient headscalev1.HeadscaleServiceClient - headscaleAddress string + Log *slog.Logger + Repo *repository.Store + HeadscaleClient headscalev1.HeadscaleServiceClient + HeadscaleControlplaneAddress string } type vpnService struct { - log *slog.Logger - repo *repository.Store - headscaleClient headscalev1.HeadscaleServiceClient - headscaleAddress string + log *slog.Logger + repo *repository.Store + headscaleClient headscalev1.HeadscaleServiceClient + headscaleControlplaneAddress string } type VPNService interface { adminv2connect.VPNServiceHandler @@ -48,10 +48,10 @@ type VPNService interface { func New(c Config) VPNService { return &vpnService{ - log: c.Log, - repo: c.Repo, - headscaleClient: c.headscaleClient, - headscaleAddress: c.headscaleAddress, + log: c.Log, + repo: c.Repo, + headscaleClient: c.HeadscaleClient, + headscaleControlplaneAddress: c.HeadscaleControlplaneAddress, } } @@ -86,13 +86,13 @@ func (v *vpnService) Authkey(ctx context.Context, req *adminv2.VPNServiceAuthkey } return &adminv2.VPNServiceAuthkeyResponse{ - Address: v.headscaleAddress, + Address: v.headscaleControlplaneAddress, Authkey: key.PreAuthKey.Key, }, nil } func (v *vpnService) ControlPlaneAddress() string { - return v.headscaleAddress + return v.headscaleControlplaneAddress } func (v *vpnService) CreateUser(ctx context.Context, name string) (*headscalev1.User, error) { diff --git a/pkg/service/vpn/admin/vpn-service_test.go b/pkg/service/vpn/admin/vpn-service_test.go index 510e13cd..a82a9a67 100644 --- a/pkg/service/vpn/admin/vpn-service_test.go +++ b/pkg/service/vpn/admin/vpn-service_test.go @@ -70,10 +70,10 @@ func Test_vpnService_Authkey(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { v := &vpnService{ - log: log, - repo: testStore.Store, - headscaleClient: headscaleClient, - headscaleAddress: endpoint, + log: log, + repo: testStore.Store, + headscaleClient: headscaleClient, + headscaleControlplaneAddress: endpoint, } got, gotErr := v.Authkey(t.Context(), tt.req) @@ -136,9 +136,9 @@ func Test_vpnService_DeleteNode(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { v := &vpnService{ - log: log, - headscaleClient: headscaleClient, - headscaleAddress: endpoint, + log: log, + headscaleClient: headscaleClient, + headscaleControlplaneAddress: endpoint, } gotErr := v.DeleteNode(ctx, tt.machineID, tt.projectID) From e02d0668e1e757d8223ef21cc251bbaf82340eff Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sat, 13 Dec 2025 09:46:16 +0100 Subject: [PATCH 04/18] Try fixing tests --- go.mod | 14 +++++----- go.sum | 34 +++++++++++------------ pkg/service/vpn/admin/vpn-service_test.go | 4 ++- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index 2a81dafb..68ec32b1 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/lestrrat-go/jwx/v3 v3.0.12 github.com/looplab/fsm v1.0.3 github.com/markbates/goth v1.82.0 - github.com/metal-stack/api v0.0.36-0.20251212082837-bc1a1e478232 + github.com/metal-stack/api v0.0.37-0.20251213084021-b4ab89573d93 github.com/metal-stack/go-ipam v1.14.13 github.com/metal-stack/masterdata-api v0.13.0 github.com/metal-stack/metal-lib v0.23.5 @@ -47,14 +47,14 @@ require ( golang.org/x/oauth2 v0.34.0 golang.org/x/sync v0.19.0 google.golang.org/grpc v1.77.0 - google.golang.org/protobuf v1.36.10 + google.golang.org/protobuf v1.36.11 gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.2 ) replace github.com/markbates/goth => github.com/metal-stack/goth v0.1.0 require ( - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20251209175733-2a1774d88802.1 // indirect + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1 // indirect cel.dev/expr v0.25.1 // indirect dario.cat/mergo v1.0.2 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect @@ -207,14 +207,14 @@ require ( go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect - golang.org/x/crypto v0.45.0 // indirect + golang.org/x/crypto v0.46.0 // indirect golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect - golang.org/x/net v0.47.0 // indirect + golang.org/x/net v0.48.0 // indirect golang.org/x/sys v0.39.0 // indirect golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect gopkg.in/cenkalti/backoff.v2 v2.2.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 79ea80f4..a2ea040e 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20251209175733-2a1774d88802.1 h1:ZnX3qpF/pDiYrf+Q3p+/zCzZ5ELSpszy5hdVarDMSV4= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.10-20251209175733-2a1774d88802.1/go.mod h1:fUl8CEN/6ZAMk6bP8ahBJPUJw7rbp+j4x+wCcYi2IG4= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1 h1:j9yeqTWEFrtimt8Nng2MIeRrpoCvQzM9/g25XTvqUGg= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= buf.build/go/protovalidate v1.1.0 h1:pQqEQRpOo4SqS60qkvmhLTTQU9JwzEvdyiqAtXa5SeY= buf.build/go/protovalidate v1.1.0/go.mod h1:bGZcPiAQDC3ErCHK3t74jSoJDFOs2JH3d7LWuTEIdss= cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= @@ -310,8 +310,8 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 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/metal-stack/api v0.0.36-0.20251212082837-bc1a1e478232 h1:aOMJXkwTIsvnjeRyl/WaoEGla21+oFyRyIO0dwOgTHg= -github.com/metal-stack/api v0.0.36-0.20251212082837-bc1a1e478232/go.mod h1:4wrEGm7Qfm/PQ9zsl64A2T9efHYL/0b21+Wjla3TF+k= +github.com/metal-stack/api v0.0.37-0.20251213084021-b4ab89573d93 h1:702psNAic44UtmaBA849DakUJZlpwFXrsH7YycMxIiE= +github.com/metal-stack/api v0.0.37-0.20251213084021-b4ab89573d93/go.mod h1:lVDIha/gViLpYuJi+OhQIQCeh6XYdzGxrtbtJTJ94eI= github.com/metal-stack/go-ipam v1.14.13 h1:/W5/MDBX5EU18xNDjlBvV6JjQ1Ot12dO2WxLvV6S8vc= github.com/metal-stack/go-ipam v1.14.13/go.mod h1:eif3UGUFP7CWJdrgLIOjhVM3G2K19GN8lhCgPVfvLDs= github.com/metal-stack/goth v0.1.0 h1:sdadAH9QG+xAjLNKAJq8+esfXct6icTs58juoR4BKrQ= @@ -451,8 +451,6 @@ github.com/tailscale/squibble v0.0.0-20251030164342-4d5df9caa993 h1:FyiiAvDAxpB0 github.com/tailscale/squibble v0.0.0-20251030164342-4d5df9caa993/go.mod h1:xJkMmR3t+thnUQhA3Q4m2VSlS5pcOq+CIjmU/xfKKx4= github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU= github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY= -github.com/testcontainers/testcontainers-go/modules/postgres v0.38.0 h1:KFdx9A0yF94K70T6ibSuvgkQQeX1xKlZVF3hEagXEtY= -github.com/testcontainers/testcontainers-go/modules/postgres v0.38.0/go.mod h1:T/QRECND6N6tAKMxF1Za+G2tpwnGEHcODzHRsgIpw9M= github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 h1:s2bIayFXlbDFexo96y+htn7FzuhpXLYJNnIuglNKqOk= github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0/go.mod h1:h+u/2KoREGTnTl9UwrQ/g+XhasAT8E6dClclAADeXoQ= github.com/testcontainers/testcontainers-go/modules/valkey v0.40.0 h1:V0zwJVnN8fOT++ySwo/P5cwd3pmXI7O4VdA7kQ+5OiM= @@ -533,8 +531,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -549,8 +547,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -581,8 +579,8 @@ golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -604,14 +602,14 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls= -google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII= gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU= diff --git a/pkg/service/vpn/admin/vpn-service_test.go b/pkg/service/vpn/admin/vpn-service_test.go index a82a9a67..9f1c9b8d 100644 --- a/pkg/service/vpn/admin/vpn-service_test.go +++ b/pkg/service/vpn/admin/vpn-service_test.go @@ -23,7 +23,6 @@ var ( ) func Test_vpnService_Authkey(t *testing.T) { - t.Parallel() log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) @@ -94,6 +93,7 @@ func Test_vpnService_Authkey(t *testing.T) { func Test_vpnService_DeleteNode(t *testing.T) { t.Skip() + t.Parallel() log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) ctx := t.Context() @@ -156,6 +156,7 @@ func Test_vpnService_DeleteNode(t *testing.T) { } func Test_vpnService_CreateUser(t *testing.T) { + t.Parallel() log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) ctx := t.Context() @@ -209,6 +210,7 @@ func Test_vpnService_CreateUser(t *testing.T) { } func Test_vpnService_UserExists(t *testing.T) { + t.Parallel() log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) ctx := t.Context() From e6464dd444f150bfa2f9865313ec62f12b3cf367 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sat, 20 Dec 2025 17:49:43 +0100 Subject: [PATCH 05/18] More tests --- .github/workflows/docker.yaml | 2 +- go.mod | 57 +++++++- go.sum | 165 ++++++++++++++++++++++ pkg/service/vpn/admin/vpn-service.go | 22 +-- pkg/service/vpn/admin/vpn-service_test.go | 118 ++++++++++------ pkg/test/headscale.go | 25 +++- 6 files changed, 329 insertions(+), 60 deletions(-) diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index c2991e2a..aeef9d22 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -33,7 +33,7 @@ jobs: cache: false - name: Lint Go - uses: golangci/golangci-lint-action@v8 + uses: golangci/golangci-lint-action@v9 - name: Build run: | diff --git a/go.mod b/go.mod index 68ec32b1..af3558a9 100644 --- a/go.mod +++ b/go.mod @@ -49,6 +49,7 @@ require ( google.golang.org/grpc v1.77.0 google.golang.org/protobuf v1.36.11 gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.2 + tailscale.com v1.86.5 ) replace github.com/markbates/goth => github.com/metal-stack/goth v0.1.0 @@ -57,25 +58,46 @@ require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1 // indirect cel.dev/expr v0.25.1 // indirect dario.cat/mergo v1.0.2 // indirect + filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Masterminds/squirrel v1.5.4 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/akutz/memconn v0.1.0 // indirect + github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.36.0 // indirect + github.com/aws/aws-sdk-go-v2/config v1.29.5 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.58 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12 // indirect + github.com/aws/aws-sdk-go-v2/service/ssm v1.45.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.13 // indirect + github.com/aws/smithy-go v1.22.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/coder/websocket v1.8.14 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v1.0.0-rc.2 // indirect + github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect github.com/coreos/go-oidc/v3 v3.17.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/creachadair/mds v0.25.10 // indirect + github.com/dblohm7/wingoes v0.0.0-20240801171404-fc12d7c70140 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/docker v28.5.2+incompatible // indirect github.com/docker/go-connections v0.6.0 // indirect @@ -86,6 +108,8 @@ require ( github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/gaissmai/bart v0.18.0 // indirect github.com/glebarez/go-sqlite v1.22.0 // indirect github.com/glebarez/sqlite v1.11.0 // indirect github.com/go-chi/chi/v5 v5.2.3 // indirect @@ -111,20 +135,28 @@ require ( github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/goccy/go-json v0.10.5 // indirect + github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v1.0.0 // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/cel-go v0.26.1 // indirect + github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect + github.com/hdevalence/ed25519consensus v0.2.0 // indirect github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0 // indirect + github.com/illarion/gonotify/v3 v3.0.2 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgx/v5 v5.7.6 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/jsimonetti/rtnetlink v1.4.1 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.2 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect @@ -140,7 +172,13 @@ require ( github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mdelapenya/tlscert v0.2.0 // indirect + github.com/mdlayher/genetlink v1.3.2 // indirect + github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect + github.com/mdlayher/sdnotify v1.0.0 // indirect + github.com/mdlayher/socket v0.5.0 // indirect + github.com/miekg/dns v1.1.58 // indirect github.com/minio/minlz v1.0.1 // indirect + github.com/mitchellh/go-ps v1.0.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/go-archive v0.1.0 // indirect github.com/moby/patternmatcher v0.6.0 // indirect @@ -162,6 +200,7 @@ require ( github.com/pkg/errors v0.9.1 // 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-community/pro-bing v0.4.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.4 // indirect github.com/prometheus/otlptranslator v1.0.0 // indirect @@ -170,6 +209,7 @@ require ( github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rs/zerolog v1.34.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/safchain/ethtool v0.3.0 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect github.com/segmentio/asm v1.2.1 // indirect github.com/shirou/gopsutil/v4 v4.25.11 // indirect @@ -181,9 +221,19 @@ require ( github.com/stoewer/go-strcase v1.3.1 // indirect github.com/stretchr/objx v0.5.3 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect + github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect + github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect + github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33 // indirect + github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 // indirect + github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect github.com/tailscale/squibble v0.0.0-20251030164342-4d5df9caa993 // indirect + github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect + github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect github.com/tklauser/numcpus v0.11.0 // indirect + github.com/vishvananda/netns v0.0.5 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.2.0 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect @@ -209,10 +259,15 @@ require ( go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect golang.org/x/crypto v0.46.0 // indirect golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect + golang.org/x/mod v0.31.0 // indirect golang.org/x/net v0.48.0 // indirect golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.40.0 // indirect + golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect + golang.zx2c4.com/wireguard/windows v0.5.3 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect gopkg.in/cenkalti/backoff.v2 v2.2.1 // indirect @@ -220,11 +275,11 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/driver/postgres v1.6.0 // indirect gorm.io/gorm v1.31.0 // indirect + gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 // indirect modernc.org/libc v1.66.10 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect modernc.org/sqlite v1.39.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect - tailscale.com v1.86.5 // indirect zgo.at/zcache/v2 v2.4.1 // indirect ) diff --git a/go.sum b/go.sum index a2ea040e..a69c10b4 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f h1:1C7nZuxUMNz7eiQALRfiqNOm04+m3edWlRff/BYHf0Q= +9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f/go.mod h1:hHyrZRryGqVdqrknjq5OWDLGCTJ2NeEvtrpR96mjraM= buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1 h1:j9yeqTWEFrtimt8Nng2MIeRrpoCvQzM9/g25XTvqUGg= buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= buf.build/go/protovalidate v1.1.0 h1:pQqEQRpOo4SqS60qkvmhLTTQU9JwzEvdyiqAtXa5SeY= @@ -18,22 +20,60 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +filippo.io/mkcert v1.4.4 h1:8eVbbwfVlaqUM7OwuftKc2nuYOoTDQWqsoXmzoXZdbc= +filippo.io/mkcert v1.4.4/go.mod h1:VyvOchVuAye3BoUsPUOOofKygVwLV2KQMVFJNRq+1dA= 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/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= 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.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A= +github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI= github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/avast/retry-go/v4 v4.7.0 h1:yjDs35SlGvKwRNSykujfjdMxMhMQQM0TnIjJaHB+Zio= github.com/avast/retry-go/v4 v4.7.0/go.mod h1:ZMPDa3sY2bKgpLtap9JRUgk2yTAba7cgiFhqxY2Sg6Q= +github.com/aws/aws-sdk-go-v2 v1.36.0 h1:b1wM5CcE65Ujwn565qcwgtOTT1aT4ADOHHgglKjG7fk= +github.com/aws/aws-sdk-go-v2 v1.36.0/go.mod h1:5PMILGVKiW32oDzjj6RU52yrNrDPUHcbZQYr1sM7qmM= +github.com/aws/aws-sdk-go-v2/config v1.29.5 h1:4lS2IB+wwkj5J43Tq/AwvnscBerBJtQQ6YS7puzCI1k= +github.com/aws/aws-sdk-go-v2/config v1.29.5/go.mod h1:SNzldMlDVbN6nWxM7XsUiNXPSa1LWlqiXtvh/1PrJGg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.58 h1:/d7FUpAPU8Lf2KUdjniQvfNdlMID0Sd9pS23FJ3SS9Y= +github.com/aws/aws-sdk-go-v2/credentials v1.17.58/go.mod h1:aVYW33Ow10CyMQGFgC0ptMRIqJWvJ4nxZb0sUiuQT/A= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 h1:7lOW8NUwE9UZekS1DYoiPdVAqZ6A+LheHWb+mHbNOq8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27/go.mod h1:w1BASFIPOPUae7AgaH4SbjNbfdkxuggLyGfNFTn8ITY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31 h1:lWm9ucLSRFiI4dQQafLrEOmEDGry3Swrz0BIRdiHJqQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31/go.mod h1:Huu6GG0YTfbPphQkDSo4dEGmQRTKb9k9G7RdtyQWxuI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31 h1:ACxDklUKKXb48+eg5ROZXi1vDgfMyfIA/WyvqHcHI0o= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31/go.mod h1:yadnfsDwqXeVaohbGc/RaD287PuyRw2wugkh5ZL2J6k= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12 h1:O+8vD2rGjfihBewr5bT+QUfYUHIxCVgG61LHoT59shM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12/go.mod h1:usVdWJaosa66NMvmCrr08NcWDBRv4E6+YFG2pUdw1Lk= +github.com/aws/aws-sdk-go-v2/service/ssm v1.45.0 h1:IOdss+igJDFdic9w3WKwxGCmHqUxydvIhJOm9LJ32Dk= +github.com/aws/aws-sdk-go-v2/service/ssm v1.45.0/go.mod h1:Q7XIWsMo0JcMpI/6TGD6XXcXcV1DbTj6e9BKNntIMIM= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 h1:c5WJ3iHz7rLIgArznb3JCSQT3uUMiz9DLZhIX+1G8ok= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.14/go.mod h1:+JJQTxB6N4niArC14YNtxcQtwEqzS3o9Z32n7q33Rfs= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 h1:f1L/JtUkVODD+k1+IiSJUUv8A++2qVr+Xvb3xWXETMU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13/go.mod h1:tvqlFoja8/s0o+UruA1Nrezo/df0PzdunMDDurUfg6U= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.13 h1:3LXNnmtH3TURctC23hnC0p/39Q5gre3FI7BNOiDcVWc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.13/go.mod h1:7Yn+p66q/jt38qMoVfNvjbm3D89mGBnkwDcijgtih8w= +github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= +github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0= @@ -46,12 +86,17 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= +github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= +github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= +github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= @@ -60,6 +105,8 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6acgLGv/QzE4= github.com/containerd/platforms v1.0.0-rc.2/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4= +github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0= +github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= @@ -73,6 +120,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3 github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creachadair/mds v0.25.10 h1:9k9JB35D1xhOCFl0liBhagBBp8fWWkKZrA7UXsfoHtA= github.com/creachadair/mds v0.25.10/go.mod h1:4hatI3hRM+qhzuAmqPRFvaBM8mONkS7nsLxkcuTYUIs= +github.com/creachadair/taskgroup v0.13.2 h1:3KyqakBuFsm3KkXi/9XIb0QcA8tEzLHLgaoidf0MdVc= +github.com/creachadair/taskgroup v0.13.2/go.mod h1:i3V1Zx7H8RjwljUEeUWYT30Lmb9poewSb2XI1yTwD0g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= @@ -80,12 +129,18 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dblohm7/wingoes v0.0.0-20240801171404-fc12d7c70140 h1:g4XyYZ0ed3hBOZPvvGadyiVfVaRsAFEVBCQGCoQC/sE= +github.com/dblohm7/wingoes v0.0.0-20240801171404-fc12d7c70140/go.mod h1:SUxUaAK/0UG5lYyZR1L1nC4AaYYvSSYTWQSH3FPcxKU= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= +github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= +github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= @@ -108,6 +163,12 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo= +github.com/gaissmai/bart v0.18.0/go.mod h1:JJzMAhNF5Rjo4SF4jWBrANuJfqY+FvsFhW7t1UZJ+XY= +github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= +github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= @@ -181,26 +242,38 @@ github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpv github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737 h1:cf60tHxREO3g1nroKr2osU3JWZsJzkfi7rEg+oAB0Lo= +github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737/go.mod h1:MIS0jDzbU/vuM9MC4YnBITCv+RYuTRq8dJzmCrFsK9g= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg= +github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU= 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/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/cel-go v0.26.1 h1:iPbVVEdkhTX++hpe3lzSk7D3G3QSYqLGoHOcEio+UXQ= github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= 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.4 h1:awZRf9FwOeTunQmHoDYSHJps3ie6f1UlhS1fOdPEt1I= +github.com/google/go-tpm v0.9.4/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI= +github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4= github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d h1:KJIErDwbSHjnp/SGzE5ed8Aol7JsKiI5X7yWKAtzhM0= github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -217,11 +290,17 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLW github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= +github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/hibiken/asynq v0.25.1 h1:phj028N0nm15n8O2ims+IvJ2gz4k2auvermngh9JhTw= github.com/hibiken/asynq v0.25.1/go.mod h1:pazWNOLBu0FEynQRBvHA26qdIKRSmfdIfUm4HdsLmXg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0 h1:nHoRIX8iXob3Y2kdt9KsjyIb7iApSvb3vgsd93xb5Ow= github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0/go.mod h1:c1tRKs5Tx7E2+uHGSyyncziFjvGpgv4H2HrqXeUQ/Uk= +github.com/illarion/gonotify/v3 v3.0.2 h1:O7S6vcopHexutmpObkeWsnzMJt/r1hONIEogeVNmJMk= +github.com/illarion/gonotify/v3 v3.0.2/go.mod h1:HWGPdPe817GfvY3w7cx6zkbzNZfi3QjcBm/wgVvEL1U= +github.com/insomniacslk/dhcp v0.0.0-20240204152450-ca2dc33955c1 h1:L3pm9Kf2G6gJVYawz2SrI5QnV1wzHYbqmKnSHHXJAb8= +github.com/insomniacslk/dhcp v0.0.0-20240204152450-ca2dc33955c1/go.mod h1:izxuNQZeFrbx2nK2fAyN5iNUB34Fe9j0nK4PwLzAkKw= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/pgconn v1.11.0 h1:HiHArx4yFbwl91X3qqIHtUFoiIfLNJXCQRsnzkiwwaQ= @@ -242,13 +321,21 @@ github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk= github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJBcYE71g= +github.com/jellydator/ttlcache/v3 v3.1.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jsimonetti/rtnetlink v1.4.1 h1:JfD4jthWBqZMEffc5RjgmlzpYttAVw1sdnmiNaPO3hE= +github.com/jsimonetti/rtnetlink v1.4.1/go.mod h1:xJjT7t59UIZ62GLZbv6PLLo8VFrostJMPBAheR6OM8w= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/juanfont/headscale v0.27.1 h1:BSvxiQX3GBgLUrAO3fpYnftnBUAUqgLkZVpS4G+b82c= @@ -259,6 +346,10 @@ github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uq github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/connect-compress/v2 v2.1.0 h1:8fM8QrVeHT69e5VVSh4yjDaQASYIvOp2uMZq7nVLj2U= github.com/klauspost/connect-compress/v2 v2.1.0/go.mod h1:Ayurh2wscMMx3AwdGGVL+ylSR5316WfApREDgsqHyH8= +github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ= +github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a/go.mod h1:YTtCCM3ryyfiu4F7t8HQ1mxvp1UBdWM2r6Xa+nGWvDk= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -310,6 +401,14 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 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/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= +github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= +github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg= +github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o= +github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ3c= +github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= +github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI= +github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI= github.com/metal-stack/api v0.0.37-0.20251213084021-b4ab89573d93 h1:702psNAic44UtmaBA849DakUJZlpwFXrsH7YycMxIiE= github.com/metal-stack/api v0.0.37-0.20251213084021-b4ab89573d93/go.mod h1:lVDIha/gViLpYuJi+OhQIQCeh6XYdzGxrtbtJTJ94eI= github.com/metal-stack/go-ipam v1.14.13 h1:/W5/MDBX5EU18xNDjlBvV6JjQ1Ot12dO2WxLvV6S8vc= @@ -324,8 +423,12 @@ github.com/metal-stack/security v0.9.5 h1:dWJP1hJxvQhdyyrmKqYxsi5sZ5Wbxa66OZBiAr github.com/metal-stack/security v0.9.5/go.mod h1:2++bUdpPbx4d7faiEUiowelT4E65U79Kcw3UOHbuw4k= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= github.com/metal-stack/v v1.0.3/go.mod h1:YTahEu7/ishwpYKnp/VaW/7nf8+PInogkfGwLcGPdXg= +github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= +github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A= github.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= +github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= +github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= @@ -355,6 +458,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -371,13 +476,19 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= +github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4= +github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= @@ -405,6 +516,8 @@ github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0= +github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs= github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= @@ -445,10 +558,32 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ= +github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4= +github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4= +github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55/go.mod h1:4k4QO+dQ3R5FofL+SanAUZe+/QfeK0+OIuwDIRu2vSg= +github.com/tailscale/golang-x-crypto v0.0.0-20250404221719-a5573b049869 h1:SRL6irQkKGQKKLzvQP/ke/2ZuB7Py5+XuqtOgSj+iMM= +github.com/tailscale/golang-x-crypto v0.0.0-20250404221719-a5573b049869/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ= +github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 h1:4chzWmimtJPxRs2O36yuGRW3f9SYV+bMTTvMBI0EKio= +github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8= github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33 h1:idh63uw+gsG05HwjZsAENCG4KZfyvjK03bpjxa5qRRk= github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33/go.mod h1:EbW0wDK/qEUYI0A5bqq0C2kF8JTQwWONmGDBbzsxxHo= +github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 h1:uFsXVBE9Qr4ZoF094vE6iYTLDl0qCiKzYXlL6UeWObU= +github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0= +github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc h1:24heQPtnFR+yfntqhI3oAu9i27nEojcQ4NuBQOo5ZFA= +github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc/go.mod h1:f93CXfllFsO9ZQVq+Zocb1Gp4G5Fz0b0rXHLOzt/Djc= github.com/tailscale/squibble v0.0.0-20251030164342-4d5df9caa993 h1:FyiiAvDAxpB0DrW2GW3KOVfi3YFOtsQUEeFWbf55JJU= github.com/tailscale/squibble v0.0.0-20251030164342-4d5df9caa993/go.mod h1:xJkMmR3t+thnUQhA3Q4m2VSlS5pcOq+CIjmU/xfKKx4= +github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 h1:UBPHPtv8+nEAy2PD8RyAhOYvau1ek0HDJqLS/Pysi14= +github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ= +github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6 h1:l10Gi6w9jxvinoiq15g8OToDdASBni4CyJOdHY1Hr8M= +github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6/go.mod h1:ZXRML051h7o4OcI0d3AaILDIad/Xw0IkXaHM17dic1Y= +github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da h1:jVRUZPRs9sqyKlYHHzHjAqKN+6e/Vog6NpHYeNPJqOw= +github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da/go.mod h1:BOm5fXUBFM+m9woLNBoxI9TaBXXhGNP50LX/TGIvGb4= +github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e h1:zOGKqN5D5hHhiYUp091JqK7DPCqSARyUfduhGUY8Bek= +github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e/go.mod h1:orPd6JZXXRyuDusYilywte7k094d7dycXXU5YnWsrwg= +github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA= +github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk= github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU= github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY= github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 h1:s2bIayFXlbDFexo96y+htn7FzuhpXLYJNnIuglNKqOk= @@ -459,12 +594,21 @@ github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYI github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= +github.com/u-root/u-root v0.14.0 h1:Ka4T10EEML7dQ5XDvO9c3MBN8z4nuSnGjcd1jmU2ivg= +github.com/u-root/u-root v0.14.0/go.mod h1:hAyZorapJe4qzbLWlAkmSVCJGbfoU9Pu4jpJ1WMluqE= +github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM= +github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= github.com/valkey-io/valkey-go v1.0.59 h1:W67Z0UY+Qqk3k8NKkFCFlM3X4yQUniixl7dSJAch2Qo= github.com/valkey-io/valkey-go v1.0.59/go.mod h1:bHmwjIEOrGq/ubOJfh5uMRs7Xj6mV3mQ/ZXUbmqpjqY= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= +github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs= @@ -535,6 +679,10 @@ golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= +golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= +golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w= +golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -555,6 +703,7 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= @@ -563,6 +712,8 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -572,6 +723,7 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -600,6 +752,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= +golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= +golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= +golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= @@ -628,6 +784,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 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.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -639,6 +796,12 @@ gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY= gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= +gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 h1:2gap+Kh/3F47cO6hAu3idFvsJ0ue6TRcEi2IUkv/F8k= +gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM= +honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I= +honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs= +howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= +howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= modernc.org/cc/v4 v4.26.5 h1:xM3bX7Mve6G8K8b+T11ReenJOT+BmVqQj0FY5T4+5Y4= modernc.org/cc/v4 v4.26.5/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= modernc.org/ccgo/v4 v4.28.1 h1:wPKYn5EC/mYTqBO373jKjvX2n+3+aK7+sICCv4Fjy1A= @@ -667,6 +830,8 @@ modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= +software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= +software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= tailscale.com v1.86.5 h1:yBtWFjuLYDmxVnfnvPbZNZcKADCYgNfMd0rUAOA9XCs= tailscale.com v1.86.5/go.mod h1:Lm8dnzU2i/Emw15r6sl3FRNp/liSQ/nYw6ZSQvIdZ1M= zgo.at/zcache/v2 v2.4.1 h1:Dfjoi8yI0Uq7NCc4lo2kaQJJmp9Mijo21gef+oJstbY= diff --git a/pkg/service/vpn/admin/vpn-service.go b/pkg/service/vpn/admin/vpn-service.go index fcb97ed6..7d3db935 100644 --- a/pkg/service/vpn/admin/vpn-service.go +++ b/pkg/service/vpn/admin/vpn-service.go @@ -42,7 +42,7 @@ type VPNService interface { UserExists(context.Context, string) (*headscalev1.User, bool) ControlPlaneAddress() string NodesConnected(context.Context) ([]*headscalev1.Node, error) - DeleteNode(ctx context.Context, machineID, projectID string) error + DeleteNode(ctx context.Context, machineID, projectID string) (*headscalev1.Node, error) EvaluateVPNConnected(ctx context.Context) error } @@ -100,26 +100,29 @@ func (v *vpnService) CreateUser(ctx context.Context, name string) (*headscalev1. Name: name, }) // TODO check if this is still like this - if err != nil && !strings.Contains(err.Error(), headscaledb.ErrUserExists.Error()) { - return nil, fmt.Errorf("failed to create new VPN user: %w", err) + if err != nil { + if strings.Contains(err.Error(), headscaledb.ErrUserExists.Error()) || strings.Contains(err.Error(), "UNIQUE constraint failed") { + return nil, errorutil.NewConflict(err) + } + return nil, err } return resp.User, nil } -func (v *vpnService) DeleteNode(ctx context.Context, machineID string, projectID string) error { +func (v *vpnService) DeleteNode(ctx context.Context, machineID string, projectID string) (*headscalev1.Node, error) { machine, err := v.getNode(ctx, machineID, projectID) - if err != nil || machine == nil { - return err + if err != nil { + return nil, err } req := &headscalev1.DeleteNodeRequest{ NodeId: machine.Id, } if _, err := v.headscaleClient.DeleteNode(ctx, req); err != nil { - return fmt.Errorf("failed to delete machine: %w", err) + return nil, fmt.Errorf("failed to delete machine: %w", err) } - return nil + return machine, nil } func (v *vpnService) NodesConnected(ctx context.Context) ([]*headscalev1.Node, error) { @@ -159,13 +162,14 @@ func (v *vpnService) getNode(ctx context.Context, machineID, projectID string) ( return nil, fmt.Errorf("failed to list nodes: %w", err) } + v.log.Debug("getNode", "nodes", resp.Nodes) for _, m := range resp.Nodes { if m.Name == machineID { return m, nil } } - return nil, nil + return nil, errorutil.NotFound("node with id %s and project %s not found", machineID, projectID) } func (v *vpnService) EvaluateVPNConnected(ctx context.Context) error { diff --git a/pkg/service/vpn/admin/vpn-service_test.go b/pkg/service/vpn/admin/vpn-service_test.go index 9f1c9b8d..996328e8 100644 --- a/pkg/service/vpn/admin/vpn-service_test.go +++ b/pkg/service/vpn/admin/vpn-service_test.go @@ -7,15 +7,18 @@ import ( "testing" "time" - "github.com/davecgh/go-spew/spew" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" v1 "github.com/juanfont/headscale/gen/go/headscale/v1" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" - "github.com/metal-stack/metal-lib/pkg/pointer" + "github.com/metal-stack/metal-apiserver/pkg/errorutil" "github.com/metal-stack/metal-apiserver/pkg/test" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" ) var ( @@ -30,7 +33,7 @@ func Test_vpnService_Authkey(t *testing.T) { testStore, repoCloser := test.StartRepositoryWithCleanup(t, log, test.WithPostgres(false)) repo := testStore.Store - headscaleClient, endpoint, headscaleCloser := test.StartHeadscale(t) + headscaleClient, endpoint, _, headscaleCloser := test.StartHeadscale(t) defer func() { repoCloser() @@ -92,12 +95,11 @@ func Test_vpnService_Authkey(t *testing.T) { } func Test_vpnService_DeleteNode(t *testing.T) { - t.Skip() t.Parallel() log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) ctx := t.Context() - headscaleClient, endpoint, headscaleCloser := test.StartHeadscale(t) + headscaleClient, endpoint, controllerURL, headscaleCloser := test.StartHeadscale(t) user, err := headscaleClient.CreateUser(ctx, &v1.CreateUserRequest{ Name: "p1", @@ -105,16 +107,13 @@ func Test_vpnService_DeleteNode(t *testing.T) { require.NoError(t, err) key, err := headscaleClient.CreatePreAuthKey(ctx, &v1.CreatePreAuthKeyRequest{ - User: user.User.Id, + User: user.User.Id, + Ephemeral: true, + Expiration: timestamppb.New(time.Now().Add(time.Minute)), }) require.NoError(t, err) - spew.Dump(key) - node, err := headscaleClient.RegisterNode(ctx, &v1.RegisterNodeRequest{ - User: "p1", - Key: key.String(), - }) - require.NoError(t, err) + test.ConnectVPNClient(t, "m1", controllerURL, key.PreAuthKey.Key) defer func() { headscaleCloser() @@ -124,13 +123,28 @@ func Test_vpnService_DeleteNode(t *testing.T) { name string machineID string projectID string - wantErr bool + want *v1.Node + wantErr error }{ { name: "delete existing node", - machineID: node.Node.Name, + machineID: "m1", + projectID: "p1", + want: &v1.Node{ + Name: "m1", + GivenName: "m1", + RegisterMethod: v1.RegisterMethod_REGISTER_METHOD_AUTH_KEY, + User: user.User, + Online: true, + }, + wantErr: nil, + }, + { + name: "delete non existing node", + machineID: "m-nonexisting", projectID: "p1", - wantErr: false, + want: nil, + wantErr: errorutil.NotFound("node with id m-nonexisting and project p1 not found"), }, } for _, tt := range tests { @@ -141,15 +155,20 @@ func Test_vpnService_DeleteNode(t *testing.T) { headscaleControlplaneAddress: endpoint, } - gotErr := v.DeleteNode(ctx, tt.machineID, tt.projectID) - if gotErr != nil { - if !tt.wantErr { - t.Errorf("DeleteNode() failed: %v", gotErr) - } + got, err := v.DeleteNode(ctx, tt.machineID, tt.projectID) + if diff := cmp.Diff(err, tt.wantErr, errorutil.ConnectErrorComparer()); diff != "" { + t.Errorf("diff = %s", diff) return } - if tt.wantErr { - t.Fatal("DeleteNode() succeeded unexpectedly") + if diff := cmp.Diff( + tt.want, got, + protocmp.Transform(), + protocmp.IgnoreFields( + &v1.Node{}, "id", "created_at", "disco_key", "expiry", "ip_addresses", "last_seen", "machine_key", "node_key", "pre_auth_key", + ), + cmpopts.IgnoreUnexported(), + ); diff != "" { + t.Errorf("%v, want %v diff: %s", got, tt.want, diff) } }) } @@ -160,7 +179,7 @@ func Test_vpnService_CreateUser(t *testing.T) { log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) ctx := t.Context() - headscaleClient, _, headscaleCloser := test.StartHeadscale(t) + headscaleClient, _, _, headscaleCloser := test.StartHeadscale(t) defer headscaleCloser() _, err := headscaleClient.CreateUser(ctx, &v1.CreateUserRequest{ @@ -171,19 +190,19 @@ func Test_vpnService_CreateUser(t *testing.T) { tests := []struct { name string username string - want *string - wantErr bool + want *v1.User + wantErr error }{ { name: "create new user", username: "p2", - want: pointer.Pointer("p2"), + want: &v1.User{Name: "p2"}, }, { name: "create existing user", username: "p1", want: nil, - wantErr: true, + wantErr: errorutil.Conflict("rpc error: code = Internal desc = failed to create user: creating user: constraint failed: UNIQUE constraint failed: users.name (2067)"), }, } for _, tt := range tests { @@ -192,18 +211,20 @@ func Test_vpnService_CreateUser(t *testing.T) { log: log, headscaleClient: headscaleClient, } - got, gotErr := v.CreateUser(t.Context(), tt.username) - if gotErr != nil { - if !tt.wantErr { - t.Errorf("CreateUser() failed: %v", gotErr) - } + got, err := v.CreateUser(t.Context(), tt.username) + if diff := cmp.Diff(err, tt.wantErr, errorutil.ConnectErrorComparer()); diff != "" { + t.Errorf("diff = %s", diff) return } - if tt.wantErr { - t.Fatal("CreateUser() succeeded unexpectedly") - } - if got.Name != *tt.want { - t.Errorf("CreateUser() got:%s want:%s", got.Name, *tt.want) + if diff := cmp.Diff( + tt.want, got, + protocmp.Transform(), + protocmp.IgnoreFields( + &v1.User{}, "id", "created_at", + ), + cmpopts.IgnoreUnexported(), + ); diff != "" { + t.Errorf("%v, want %v diff: %s", got, tt.want, diff) } }) } @@ -214,7 +235,7 @@ func Test_vpnService_UserExists(t *testing.T) { log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) ctx := t.Context() - headscaleClient, _, headscaleCloser := test.StartHeadscale(t) + headscaleClient, _, _, headscaleCloser := test.StartHeadscale(t) defer headscaleCloser() _, err := headscaleClient.CreateUser(ctx, &v1.CreateUserRequest{ @@ -225,13 +246,13 @@ func Test_vpnService_UserExists(t *testing.T) { tests := []struct { name string username string - want *string + want *v1.User want2 bool }{ { name: "get existing user", username: "p1", - want: pointer.Pointer("p1"), + want: &v1.User{Name: "p1"}, want2: true, }, { @@ -248,14 +269,19 @@ func Test_vpnService_UserExists(t *testing.T) { headscaleClient: headscaleClient, } got, got2 := v.UserExists(context.Background(), tt.username) - if got2 != tt.want2 { - t.Errorf("UserExists() = %v, want %v", got2, tt.want2) - } - if !got2 { + if diff := cmp.Diff(got2, tt.want2); diff != "" { + t.Errorf("diff = %s", diff) return } - if got.Name != *tt.want { - t.Errorf("UserExists() got:%s want:%s", got.Name, *tt.want) + if diff := cmp.Diff( + tt.want, got, + protocmp.Transform(), + protocmp.IgnoreFields( + &v1.User{}, "id", "created_at", + ), + cmpopts.IgnoreUnexported(), + ); diff != "" { + t.Errorf("%v, want %v diff: %s", got, tt.want, diff) } }) } diff --git a/pkg/test/headscale.go b/pkg/test/headscale.go index 0b8a55c8..df2f7851 100644 --- a/pkg/test/headscale.go +++ b/pkg/test/headscale.go @@ -9,6 +9,7 @@ import ( "time" headscalev1 "github.com/juanfont/headscale/gen/go/headscale/v1" + "tailscale.com/tsnet" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -23,7 +24,7 @@ import ( //go:embed headscale-config.yaml var headscaleConfig string -func StartHeadscale(t testing.TB) (headscalev1.HeadscaleServiceClient, string, func()) { +func StartHeadscale(t testing.TB) (headscalev1.HeadscaleServiceClient, string, string, func()) { ctx := t.Context() headscaleContainer, err := testcontainers.Run( @@ -38,7 +39,7 @@ func StartHeadscale(t testing.TB) (headscalev1.HeadscaleServiceClient, string, f "/tmp": "rw", "/var/lib/headscsale": "rw", }), - testcontainers.WithExposedPorts("50443/tcp"), + testcontainers.WithExposedPorts("8080/tcp", "50443/tcp"), testcontainers.WithWaitStrategy(wait.ForListeningPort("50443/tcp").WithStartupTimeout(time.Second*5)), testcontainers.WithCmd("serve", "-c", "/config.yaml"), testcontainers.WithLogger(tlog.TestLogger(t)), @@ -58,6 +59,9 @@ func StartHeadscale(t testing.TB) (headscalev1.HeadscaleServiceClient, string, f endpoint, err = headscaleContainer.PortEndpoint(ctx, "50443/tcp", "") require.NoError(t, err) t.Log(endpoint) + controllerURL, err := headscaleContainer.PortEndpoint(ctx, "8080/tcp", "http") + require.NoError(t, err) + t.Log(controllerURL) grpcOptions := []grpc.DialOption{ grpc.WithTransportCredentials(insecure.NewCredentials()), @@ -78,7 +82,22 @@ func StartHeadscale(t testing.TB) (headscalev1.HeadscaleServiceClient, string, f _ = headscaleContainer.Terminate(ctx) } - return client, endpoint, closer + return client, endpoint, controllerURL, closer +} + +func ConnectVPNClient(t testing.TB, hostname, controllerURL, authkey string) { + s := &tsnet.Server{ + Hostname: hostname, + ControlURL: controllerURL, + AuthKey: authkey, + } + lc, err := s.LocalClient() + require.NoError(t, err) + require.EventuallyWithT(t, func(c *assert.CollectT) { + status, err := lc.Status(t.Context()) + require.NoError(c, err) + require.True(c, status.Self.Online) + }, 10*time.Second, 50*time.Millisecond) } type tokenAuth struct { From 3695703bc8d2d8d9e273a9388b91a1fcaff4bdca Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sun, 21 Dec 2025 14:43:45 +0100 Subject: [PATCH 06/18] More tests --- cmd/server/vpn-cmd.go | 3 +- go.mod | 4 +- go.sum | 4 +- pkg/repository/machine.go | 14 +- pkg/service/vpn/admin/vpn-service.go | 75 +++++--- pkg/service/vpn/admin/vpn-service_test.go | 214 ++++++++++++++++++++-- 6 files changed, 262 insertions(+), 52 deletions(-) diff --git a/cmd/server/vpn-cmd.go b/cmd/server/vpn-cmd.go index 8730a982..888e3228 100644 --- a/cmd/server/vpn-cmd.go +++ b/cmd/server/vpn-cmd.go @@ -65,7 +65,8 @@ func newVPNCmd() *cli.Command { HeadscaleClient: hc, }) - return vpnService.EvaluateVPNConnected(ctx.Context) + _, err = vpnService.EvaluateVPNConnected(ctx.Context) + return err }, }, }, diff --git a/go.mod b/go.mod index af3558a9..d61da025 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/Masterminds/semver/v3 v3.4.0 github.com/alicebob/miniredis/v2 v2.35.0 github.com/avast/retry-go/v4 v4.7.0 - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/golang-jwt/jwt/v5 v5.3.0 github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 @@ -26,7 +25,7 @@ require ( github.com/lestrrat-go/jwx/v3 v3.0.12 github.com/looplab/fsm v1.0.3 github.com/markbates/goth v1.82.0 - github.com/metal-stack/api v0.0.37-0.20251213084021-b4ab89573d93 + github.com/metal-stack/api v0.0.37-0.20251221083840-3f9177e3233f github.com/metal-stack/go-ipam v1.14.13 github.com/metal-stack/masterdata-api v0.13.0 github.com/metal-stack/metal-lib v0.23.5 @@ -94,6 +93,7 @@ require ( github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/creachadair/mds v0.25.10 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dblohm7/wingoes v0.0.0-20240801171404-fc12d7c70140 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect diff --git a/go.sum b/go.sum index a69c10b4..e9838779 100644 --- a/go.sum +++ b/go.sum @@ -409,8 +409,8 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI= github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI= -github.com/metal-stack/api v0.0.37-0.20251213084021-b4ab89573d93 h1:702psNAic44UtmaBA849DakUJZlpwFXrsH7YycMxIiE= -github.com/metal-stack/api v0.0.37-0.20251213084021-b4ab89573d93/go.mod h1:lVDIha/gViLpYuJi+OhQIQCeh6XYdzGxrtbtJTJ94eI= +github.com/metal-stack/api v0.0.37-0.20251221083840-3f9177e3233f h1:/nhmgT8oWkokbPx3yjegukn66s9aheGFqkDUUMe3s/o= +github.com/metal-stack/api v0.0.37-0.20251221083840-3f9177e3233f/go.mod h1:lVDIha/gViLpYuJi+OhQIQCeh6XYdzGxrtbtJTJ94eI= github.com/metal-stack/go-ipam v1.14.13 h1:/W5/MDBX5EU18xNDjlBvV6JjQ1Ot12dO2WxLvV6S8vc= github.com/metal-stack/go-ipam v1.14.13/go.mod h1:eif3UGUFP7CWJdrgLIOjhVM3G2K19GN8lhCgPVfvLDs= github.com/metal-stack/goth v0.1.0 h1:sdadAH9QG+xAjLNKAJq8+esfXct6icTs58juoR4BKrQ= diff --git a/pkg/repository/machine.go b/pkg/repository/machine.go index 193d5e6c..987539bb 100644 --- a/pkg/repository/machine.go +++ b/pkg/repository/machine.go @@ -28,21 +28,25 @@ type ( } ) -func (r *machineRepository) SetMachineConnectedToVPN(ctx context.Context, id string, connected bool, ips []string) error { +func (r *machineRepository) SetMachineConnectedToVPN(ctx context.Context, id string, connected bool, ips []string) (*apiv2.Machine, error) { m, err := r.get(ctx, id) if err != nil { - return err + return nil, err } if m.Allocation == nil { - return errorutil.InvalidArgument("machine is not allocated") + return nil, errorutil.InvalidArgument("machine is not allocated") } if m.Allocation.VPN == nil { - return errorutil.InvalidArgument("machine is not configured for VPN") + return nil, errorutil.InvalidArgument("machine is not configured for VPN") } m.Allocation.VPN.Connected = connected m.Allocation.VPN.IPs = ips - return r.s.ds.Machine().Update(ctx, m) + err = r.s.ds.Machine().Update(ctx, m) + if err != nil { + return nil, err + } + return r.convertToProto(ctx, m) } func (r *machineRepository) SendEvent(ctx context.Context, log *slog.Logger, machineID string, event *infrav2.MachineProvisioningEvent) error { diff --git a/pkg/service/vpn/admin/vpn-service.go b/pkg/service/vpn/admin/vpn-service.go index 7d3db935..875dd4bd 100644 --- a/pkg/service/vpn/admin/vpn-service.go +++ b/pkg/service/vpn/admin/vpn-service.go @@ -36,14 +36,20 @@ type vpnService struct { headscaleClient headscalev1.HeadscaleServiceClient headscaleControlplaneAddress string } + type VPNService interface { adminv2connect.VPNServiceHandler + // CreateUser creates a user which maps to a metal project in headscale CreateUser(context.Context, string) (*headscalev1.User, error) - UserExists(context.Context, string) (*headscalev1.User, bool) - ControlPlaneAddress() string - NodesConnected(context.Context) ([]*headscalev1.Node, error) + // DeleteNode deletes a node in headscale DeleteNode(ctx context.Context, machineID, projectID string) (*headscalev1.Node, error) - EvaluateVPNConnected(ctx context.Context) error + // EvaluateVPNConnected iterates over all connected nodes and + // updates the machines with the online status in the vpn and their vpn ip adressess + // It returns the updated machines, machines which already have the correct + // online status and ip adressess are not touched + EvaluateVPNConnected(ctx context.Context) ([]*apiv2.Machine, error) + // ControlPlaneAddress returns the address of headscale where tailscale clients must connect to + ControlPlaneAddress() string } func New(c Config) VPNService { @@ -61,7 +67,7 @@ func (v *vpnService) Authkey(ctx context.Context, req *adminv2.VPNServiceAuthkey return nil, err } - headscaleUser, ok := v.UserExists(ctx, req.Project) + headscaleUser, ok := v.userExists(ctx, req.Project) if !ok { user, err := v.CreateUser(ctx, req.Project) if err != nil { @@ -125,16 +131,32 @@ func (v *vpnService) DeleteNode(ctx context.Context, machineID string, projectID return machine, nil } -func (v *vpnService) NodesConnected(ctx context.Context) ([]*headscalev1.Node, error) { - resp, err := v.headscaleClient.ListNodes(ctx, &headscalev1.ListNodesRequest{}) - if err != nil || resp == nil { +// ListNodes implements [VPNService]. +func (v *vpnService) ListNodes(ctx context.Context, req *adminv2.VPNServiceListNodesRequest) (*adminv2.VPNServiceListNodesResponse, error) { + lnr := &headscalev1.ListNodesRequest{} + if req.User != nil { + lnr.User = *req.User + } + resp, err := v.headscaleClient.ListNodes(ctx, lnr) + if err != nil { return nil, fmt.Errorf("failed to list machines: %w", err) } + var vpnNodes []*apiv2.VPNNode + for _, node := range resp.Nodes { + vpnNodes = append(vpnNodes, &apiv2.VPNNode{ + Id: node.Id, + Name: node.Name, + User: &node.User.Name, + IpAddresses: node.IpAddresses, + LastSeen: node.LastSeen, + Online: node.Online, + }) + } - return resp.Nodes, nil + return &adminv2.VPNServiceListNodesResponse{Nodes: vpnNodes}, nil } -func (v *vpnService) UserExists(ctx context.Context, name string) (*headscalev1.User, bool) { +func (v *vpnService) userExists(ctx context.Context, name string) (*headscalev1.User, bool) { resp, err := v.headscaleClient.ListUsers(ctx, &headscalev1.ListUsersRequest{ Name: name, }) @@ -172,7 +194,7 @@ func (v *vpnService) getNode(ctx context.Context, machineID, projectID string) ( return nil, errorutil.NotFound("node with id %s and project %s not found", machineID, projectID) } -func (v *vpnService) EvaluateVPNConnected(ctx context.Context) error { +func (v *vpnService) EvaluateVPNConnected(ctx context.Context) ([]*apiv2.Machine, error) { ms, err := v.repo.UnscopedMachine().List(ctx, &apiv2.MachineQuery{ Allocation: &apiv2.MachineAllocationQuery{ // Return only allocation machines which have a vpn configured @@ -180,30 +202,34 @@ func (v *vpnService) EvaluateVPNConnected(ctx context.Context) error { }, }) if err != nil { - return err + return nil, err } ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) defer cancel() - headscaleNodes, err := v.NodesConnected(ctx) + listNodesResp, err := v.ListNodes(ctx, &adminv2.VPNServiceListNodesRequest{}) if err != nil { - return err + return nil, err } - var errs []error + v.log.Debug("evaluated vpn connected", "machines", ms, "nodes", listNodesResp.Nodes) + + var ( + errs []error + updatedMachines []*apiv2.Machine + ) for _, m := range ms { - m := m if m.Allocation == nil || m.Allocation.Vpn == nil { continue } - index := slices.IndexFunc(headscaleNodes, func(hm *headscalev1.Node) bool { - if hm.Name != m.Uuid { + index := slices.IndexFunc(listNodesResp.Nodes, func(node *apiv2.VPNNode) bool { + if node.Name != m.Uuid { return false } - if pointer.SafeDeref(hm.User).Name != m.Allocation.Project { + if pointer.SafeDeref(node.User) != m.Allocation.Project { return false } @@ -214,27 +240,28 @@ func (v *vpnService) EvaluateVPNConnected(ctx context.Context) error { continue } - connected := headscaleNodes[index].Online - ips := headscaleNodes[index].IpAddresses + connected := listNodesResp.Nodes[index].Online + ips := listNodesResp.Nodes[index].IpAddresses if m.Allocation.Vpn.Connected == connected && slices.Equal(m.Allocation.Vpn.Ips, ips) { v.log.Info("not updating vpn because already up-to-date", "machine", m.Uuid, "connected", connected, "ips", ips) continue } - err = v.repo.UnscopedMachine().AdditionalMethods().SetMachineConnectedToVPN(ctx, m.Uuid, connected, ips) + updatedMachine, err := v.repo.UnscopedMachine().AdditionalMethods().SetMachineConnectedToVPN(ctx, m.Uuid, connected, ips) if err != nil { errs = append(errs, err) v.log.Error("unable to update vpn connected state, continue anyway", "machine", m.Uuid, "error", err) continue } + updatedMachines = append(updatedMachines, updatedMachine) v.log.Info("updated vpn connected state", "machine", m.Uuid, "connected", connected, "ips", ips) } if len(errs) > 0 { - return fmt.Errorf("errors occurred when evaluating machine vpn connections:%w", errors.Join(errs...)) + return nil, fmt.Errorf("errors occurred when evaluating machine vpn connections:%w", errors.Join(errs...)) } - return nil + return updatedMachines, nil } diff --git a/pkg/service/vpn/admin/vpn-service_test.go b/pkg/service/vpn/admin/vpn-service_test.go index 996328e8..d0e316eb 100644 --- a/pkg/service/vpn/admin/vpn-service_test.go +++ b/pkg/service/vpn/admin/vpn-service_test.go @@ -2,7 +2,10 @@ package admin import ( "context" + "fmt" "log/slog" + "net/http" + "net/http/httptest" "os" "testing" "time" @@ -13,6 +16,7 @@ import ( adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + "github.com/metal-stack/metal-apiserver/pkg/db/metal" "github.com/metal-stack/metal-apiserver/pkg/errorutil" "github.com/metal-stack/metal-apiserver/pkg/test" "github.com/stretchr/testify/require" @@ -22,7 +26,12 @@ import ( ) var ( + m1 = "00000000-0000-0000-0000-000000000001" + m2 = "00000000-0000-0000-0000-000000000002" + p0 = "00000000-0000-0000-0000-000000000000" + p1 = "00000000-0000-0000-0000-000000000001" + p2 = "00000000-0000-0000-0000-000000000002" ) func Test_vpnService_Authkey(t *testing.T) { @@ -102,7 +111,7 @@ func Test_vpnService_DeleteNode(t *testing.T) { headscaleClient, endpoint, controllerURL, headscaleCloser := test.StartHeadscale(t) user, err := headscaleClient.CreateUser(ctx, &v1.CreateUserRequest{ - Name: "p1", + Name: p1, }) require.NoError(t, err) @@ -113,7 +122,7 @@ func Test_vpnService_DeleteNode(t *testing.T) { }) require.NoError(t, err) - test.ConnectVPNClient(t, "m1", controllerURL, key.PreAuthKey.Key) + test.ConnectVPNClient(t, m1, controllerURL, key.PreAuthKey.Key) defer func() { headscaleCloser() @@ -128,11 +137,11 @@ func Test_vpnService_DeleteNode(t *testing.T) { }{ { name: "delete existing node", - machineID: "m1", - projectID: "p1", + machineID: m1, + projectID: p1, want: &v1.Node{ - Name: "m1", - GivenName: "m1", + Name: m1, + GivenName: m1, RegisterMethod: v1.RegisterMethod_REGISTER_METHOD_AUTH_KEY, User: user.User, Online: true, @@ -142,9 +151,9 @@ func Test_vpnService_DeleteNode(t *testing.T) { { name: "delete non existing node", machineID: "m-nonexisting", - projectID: "p1", + projectID: p1, want: nil, - wantErr: errorutil.NotFound("node with id m-nonexisting and project p1 not found"), + wantErr: errorutil.NotFound("node with id m-nonexisting and project %s not found", p1), }, } for _, tt := range tests { @@ -183,7 +192,7 @@ func Test_vpnService_CreateUser(t *testing.T) { defer headscaleCloser() _, err := headscaleClient.CreateUser(ctx, &v1.CreateUserRequest{ - Name: "p1", + Name: p1, }) require.NoError(t, err) @@ -195,12 +204,12 @@ func Test_vpnService_CreateUser(t *testing.T) { }{ { name: "create new user", - username: "p2", - want: &v1.User{Name: "p2"}, + username: p2, + want: &v1.User{Name: p2}, }, { name: "create existing user", - username: "p1", + username: p1, want: nil, wantErr: errorutil.Conflict("rpc error: code = Internal desc = failed to create user: creating user: constraint failed: UNIQUE constraint failed: users.name (2067)"), }, @@ -230,7 +239,7 @@ func Test_vpnService_CreateUser(t *testing.T) { } } -func Test_vpnService_UserExists(t *testing.T) { +func Test_vpnService_userExists(t *testing.T) { t.Parallel() log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) @@ -239,7 +248,7 @@ func Test_vpnService_UserExists(t *testing.T) { defer headscaleCloser() _, err := headscaleClient.CreateUser(ctx, &v1.CreateUserRequest{ - Name: "p1", + Name: p1, }) require.NoError(t, err) @@ -251,13 +260,13 @@ func Test_vpnService_UserExists(t *testing.T) { }{ { name: "get existing user", - username: "p1", - want: &v1.User{Name: "p1"}, + username: p1, + want: &v1.User{Name: p1}, want2: true, }, { name: "get non existing user", - username: "p2", + username: p2, want: nil, want2: false, }, @@ -268,7 +277,7 @@ func Test_vpnService_UserExists(t *testing.T) { log: log, headscaleClient: headscaleClient, } - got, got2 := v.UserExists(context.Background(), tt.username) + got, got2 := v.userExists(context.Background(), tt.username) if diff := cmp.Diff(got2, tt.want2); diff != "" { t.Errorf("diff = %s", diff) return @@ -286,3 +295,172 @@ func Test_vpnService_UserExists(t *testing.T) { }) } } + +func Test_vpnService_EvaluateVPNConnected(t *testing.T) { + t.Parallel() + + log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) + ctx := t.Context() + + testStore, repocloser := test.StartRepositoryWithCleanup(t, log) + repo := testStore.Store + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = fmt.Fprintln(w, "a image") + })) + + validURL := ts.URL + defer ts.Close() + + headscaleClient, endpoint, controllerURL, headscaleCloser := test.StartHeadscale(t) + + user, err := headscaleClient.CreateUser(ctx, &v1.CreateUserRequest{ + Name: p1, + }) + require.NoError(t, err) + + key, err := headscaleClient.CreatePreAuthKey(ctx, &v1.CreatePreAuthKeyRequest{ + User: user.User.Id, + Ephemeral: true, + Expiration: timestamppb.New(time.Now().Add(time.Minute)), + }) + require.NoError(t, err) + + test.CreateTenants(t, testStore, []*apiv2.TenantServiceCreateRequest{{Name: "t1"}}) + test.CreateProjects(t, repo, []*apiv2.ProjectServiceCreateRequest{{Name: p1, Login: "t1"}, {Name: p2, Login: "t1"}}) + test.CreatePartitions(t, repo, []*adminv2.PartitionServiceCreateRequest{ + { + Partition: &apiv2.Partition{Id: "partition-1", BootConfiguration: &apiv2.PartitionBootConfiguration{ImageUrl: validURL, KernelUrl: validURL}}, + }, + }) + test.CreateSizes(t, repo, []*adminv2.SizeServiceCreateRequest{ + { + Size: &apiv2.Size{Id: "c1-large-x86"}, + }, + }) + test.CreateImages(t, repo, []*adminv2.ImageServiceCreateRequest{ + {Image: &apiv2.Image{Id: "debian-12", Url: validURL, Features: []apiv2.ImageFeature{apiv2.ImageFeature_IMAGE_FEATURE_MACHINE}}}, + }) + + defer func() { + repocloser() + headscaleCloser() + }() + + tests := []struct { + name string + nodesToCreate []string + machinesToCreate []*metal.Machine + want []*apiv2.Machine + wantErr error + }{ + { + name: "one node, no machines", + nodesToCreate: []string{m1}, + want: nil, + wantErr: nil, + }, + { + name: "one node, one machine", + nodesToCreate: []string{m1}, + machinesToCreate: []*metal.Machine{ + { + Base: metal.Base{ID: m1}, + PartitionID: "partition-1", SizeID: "c1-large-x86", + Allocation: &metal.MachineAllocation{Project: p1, ImageID: "debian-12", VPN: &metal.MachineVPN{ControlPlaneAddress: endpoint}}, + }, + }, + want: []*apiv2.Machine{{ + Meta: &apiv2.Meta{}, + Uuid: m1, + Partition: &apiv2.Partition{Meta: &apiv2.Meta{}, Id: "partition-1", BootConfiguration: &apiv2.PartitionBootConfiguration{ImageUrl: validURL, KernelUrl: validURL}}, + Size: &apiv2.Size{Meta: &apiv2.Meta{}, Id: "c1-large-x86"}, + Allocation: &apiv2.MachineAllocation{ + Meta: &apiv2.Meta{}, + Project: p1, + Image: &apiv2.Image{}, + Vpn: &apiv2.MachineVPN{ + ControlPlaneAddress: endpoint, + Connected: true, + Ips: []string{"100.64.0.1", "fd7a:115c:a1e0::1"}, + }, + }, + Bios: &apiv2.MachineBios{}, + Hardware: &apiv2.MachineHardware{}, + }}, + wantErr: nil, + }, + + { + name: "one more node, one more machine", + nodesToCreate: []string{m2}, + machinesToCreate: []*metal.Machine{ + { + Base: metal.Base{ID: m2}, + PartitionID: "partition-1", SizeID: "c1-large-x86", + Allocation: &metal.MachineAllocation{Project: p1, ImageID: "debian-12", VPN: &metal.MachineVPN{ControlPlaneAddress: endpoint}}, + }, + }, + want: []*apiv2.Machine{{ + Meta: &apiv2.Meta{}, + Uuid: m2, + Partition: &apiv2.Partition{Meta: &apiv2.Meta{}, Id: "partition-1", BootConfiguration: &apiv2.PartitionBootConfiguration{ImageUrl: validURL, KernelUrl: validURL}}, + Size: &apiv2.Size{Meta: &apiv2.Meta{}, Id: "c1-large-x86"}, + Allocation: &apiv2.MachineAllocation{ + Meta: &apiv2.Meta{}, + Project: p1, + Image: &apiv2.Image{}, + Vpn: &apiv2.MachineVPN{ + ControlPlaneAddress: endpoint, + Connected: true, + Ips: []string{"100.64.0.1", "fd7a:115c:a1e0::1"}, // TODO not sure why the same ip ? + }, + }, + Bios: &apiv2.MachineBios{}, + Hardware: &apiv2.MachineHardware{}, + }}, + wantErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + for _, n := range tt.nodesToCreate { + test.ConnectVPNClient(t, n, controllerURL, key.PreAuthKey.Key) + } + test.CreateMachines(t, testStore, tt.machinesToCreate) + + v := &vpnService{ + log: log, + repo: testStore.Store, + headscaleClient: headscaleClient, + } + got, err := v.EvaluateVPNConnected(ctx) + if diff := cmp.Diff(err, tt.wantErr, errorutil.ConnectErrorComparer()); diff != "" { + t.Errorf("diff = %s", diff) + return + } + if diff := cmp.Diff( + tt.want, got, + protocmp.Transform(), + protocmp.IgnoreFields( + &apiv2.Machine{}, "meta", "status", "recent_provisioning_events", + ), + protocmp.IgnoreFields( + &apiv2.Meta{}, "created_at", "updated_at", + ), + protocmp.IgnoreFields( + &apiv2.Image{}, "classification", "description", "expires_at", "features", "id", "meta", "name", "url", + ), + protocmp.IgnoreFields( + &apiv2.MachineBios{}, + ), + protocmp.IgnoreFields( + &apiv2.MachineHardware{}, + ), + cmpopts.IgnoreUnexported(), + ); diff != "" { + t.Errorf("%v, want %v diff: %s", got, tt.want, diff) + } + }) + } +} From c578b11373c236499fc6efe629875694832e0373 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sun, 21 Dec 2025 14:59:56 +0100 Subject: [PATCH 07/18] fix --- pkg/request/tokenpermissions_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/request/tokenpermissions_test.go b/pkg/request/tokenpermissions_test.go index 42fa6672..3560bd2e 100644 --- a/pkg/request/tokenpermissions_test.go +++ b/pkg/request/tokenpermissions_test.go @@ -82,6 +82,7 @@ func Test_getTokenPermissions(t *testing.T) { "/metalstack.admin.v2.TokenService/List": {"*": {}}, "/metalstack.admin.v2.TokenService/Revoke": {"*": {}}, "/metalstack.admin.v2.VPNService/Authkey": {"*": {}}, + "/metalstack.admin.v2.VPNService/ListNodes": {"*": {}}, "/metalstack.api.v2.FilesystemService/Get": {"*": {}}, "/metalstack.api.v2.FilesystemService/List": {"*": {}}, "/metalstack.api.v2.FilesystemService/Match": {"*": {}}, From 0a8defbd196d12f8ce1a455a151abe696d8a8dfa Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sun, 21 Dec 2025 21:59:17 +0100 Subject: [PATCH 08/18] create headscale client package --- cmd/server/serve-cmd.go | 55 +++++--------------------------------- cmd/server/vpn-cmd.go | 8 +++++- pkg/headscale/client.go | 58 +++++++++++++++++++++++++++++++++++++++++ pkg/test/headscale.go | 20 ++++++-------- 4 files changed, 80 insertions(+), 61 deletions(-) create mode 100644 pkg/headscale/client.go diff --git a/cmd/server/serve-cmd.go b/cmd/server/serve-cmd.go index de9e7a8d..928c1312 100644 --- a/cmd/server/serve-cmd.go +++ b/cmd/server/serve-cmd.go @@ -1,7 +1,6 @@ package main import ( - "context" "fmt" "log/slog" "net/http" @@ -13,16 +12,13 @@ import ( "github.com/alicebob/miniredis/v2" "github.com/avast/retry-go/v4" compress "github.com/klauspost/connect-compress/v2" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" "gopkg.in/rethinkdb/rethinkdb-go.v6" - headscalev1 "github.com/juanfont/headscale/gen/go/headscale/v1" - ipamv1 "github.com/metal-stack/go-ipam/api/v1" ipamv1connect "github.com/metal-stack/go-ipam/api/v1/apiv1connect" mdm "github.com/metal-stack/masterdata-api/pkg/client" "github.com/metal-stack/metal-apiserver/pkg/db/generic" + "github.com/metal-stack/metal-apiserver/pkg/headscale" "github.com/metal-stack/metal-apiserver/pkg/repository" "github.com/metal-stack/metal-apiserver/pkg/service" "github.com/metal-stack/metal-apiserver/pkg/test" @@ -106,7 +102,12 @@ func newServeCmd() *cli.Command { return fmt.Errorf("unable to create masterdata.client: %w", err) } - hc, err := createHeadscaleClient(ctx, log) + hc, err := headscale.NewClient(headscale.Config{ + Log: log, + Disabled: !ctx.Bool(headscaleEnabledFlag.Name), + Apikey: ctx.String(headscaleApikeyFlag.Name), + Endpoint: ctx.String(headscaleAddressFlag.Name), + }) if err != nil { return err } @@ -350,45 +351,3 @@ func createIpamClient(cli *cli.Context, log *slog.Logger) (ipamv1connect.IpamSer log.Info("ipam initialized") return ipamService, nil } - -func createHeadscaleClient(cli *cli.Context, log *slog.Logger) (headscalev1.HeadscaleServiceClient, error) { - if !cli.Bool(headscaleEnabledFlag.Name) { - log.Info("headscale is not enabled, not configuring vpn services") - return nil, nil - } - - apikey := cli.String(headscaleApikeyFlag.Name) - endpoint := cli.String(headscaleAddressFlag.Name) - - grpcOptions := []grpc.DialOption{ - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithPerRPCCredentials(tokenAuth{ - token: apikey, - }), - } - - conn, err := grpc.NewClient(endpoint, grpcOptions...) - if err != nil { - return nil, fmt.Errorf("unable to create grpc client:%w", err) - } - client := headscalev1.NewHeadscaleServiceClient(conn) - - return client, nil -} - -type tokenAuth struct { - token string -} - -func (t tokenAuth) GetRequestMetadata( - ctx context.Context, - _ ...string, -) (map[string]string, error) { - return map[string]string{ - "authorization": "Bearer " + t.token, - }, nil -} - -func (tokenAuth) RequireTransportSecurity() bool { - return false -} diff --git a/cmd/server/vpn-cmd.go b/cmd/server/vpn-cmd.go index 888e3228..a3f2a843 100644 --- a/cmd/server/vpn-cmd.go +++ b/cmd/server/vpn-cmd.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/metal-stack/metal-apiserver/pkg/db/generic" + "github.com/metal-stack/metal-apiserver/pkg/headscale" "github.com/metal-stack/metal-apiserver/pkg/repository" vpnadmin "github.com/metal-stack/metal-apiserver/pkg/service/vpn/admin" "github.com/urfave/cli/v2" @@ -32,7 +33,12 @@ func newVPNCmd() *cli.Command { return fmt.Errorf("unable to create logger %w", err) } - hc, err := createHeadscaleClient(ctx, log) + hc, err := headscale.NewClient(headscale.Config{ + Log: log, + Disabled: !ctx.Bool(headscaleEnabledFlag.Name), + Apikey: ctx.String(headscaleApikeyFlag.Name), + Endpoint: ctx.String(headscaleAddressFlag.Name), + }) if err != nil { return err } diff --git a/pkg/headscale/client.go b/pkg/headscale/client.go new file mode 100644 index 00000000..ef24f7ba --- /dev/null +++ b/pkg/headscale/client.go @@ -0,0 +1,58 @@ +package headscale + +import ( + "context" + "fmt" + "log/slog" + + headscalev1 "github.com/juanfont/headscale/gen/go/headscale/v1" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type Config struct { + Log *slog.Logger + Disabled bool + Apikey string + Endpoint string +} + +func NewClient(cfg Config) (headscalev1.HeadscaleServiceClient, error) { + if cfg.Disabled { + cfg.Log.Info("headscale is not enabled, not configuring vpn services") + return nil, nil + } + + grpcOptions := []grpc.DialOption{ + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithPerRPCCredentials(tokenAuth{ + token: cfg.Apikey, + }), + } + + conn, err := grpc.NewClient(cfg.Endpoint, grpcOptions...) + if err != nil { + return nil, fmt.Errorf("unable to create grpc client:%w", err) + } + client := headscalev1.NewHeadscaleServiceClient(conn) + + return client, nil +} + +type tokenAuth struct { + token string +} + +func (t tokenAuth) GetRequestMetadata( + ctx context.Context, + _ ...string, +) (map[string]string, error) { + return map[string]string{ + "authorization": "Bearer " + t.token, + }, nil +} + +func (tokenAuth) RequireTransportSecurity() bool { + return false +} diff --git a/pkg/test/headscale.go b/pkg/test/headscale.go index df2f7851..b997e18c 100644 --- a/pkg/test/headscale.go +++ b/pkg/test/headscale.go @@ -4,11 +4,14 @@ import ( "context" _ "embed" "io" + "log/slog" + "os" "strings" "testing" "time" headscalev1 "github.com/juanfont/headscale/gen/go/headscale/v1" + "github.com/metal-stack/metal-apiserver/pkg/headscale" "tailscale.com/tsnet" "github.com/stretchr/testify/assert" @@ -17,8 +20,6 @@ import ( "github.com/testcontainers/testcontainers-go/exec" tlog "github.com/testcontainers/testcontainers-go/log" "github.com/testcontainers/testcontainers-go/wait" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" ) //go:embed headscale-config.yaml @@ -63,18 +64,13 @@ func StartHeadscale(t testing.TB) (headscalev1.HeadscaleServiceClient, string, s require.NoError(t, err) t.Log(controllerURL) - grpcOptions := []grpc.DialOption{ - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithPerRPCCredentials(tokenAuth{ - token: apikey, - }), - } - - conn, err := grpc.NewClient(endpoint, grpcOptions...) + client, err := headscale.NewClient(headscale.Config{ + Log: slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{})), + Apikey: apikey, + Endpoint: endpoint, + }) require.NoError(t, err) - client := headscalev1.NewHeadscaleServiceClient(conn) - _, err = client.Health(ctx, &headscalev1.HealthRequest{}) require.NoError(t, err) From ffdd76001e2c785bb19892f99aacadd26adecacd Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sun, 21 Dec 2025 22:06:08 +0100 Subject: [PATCH 09/18] fix --- pkg/test/headscale.go | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/pkg/test/headscale.go b/pkg/test/headscale.go index b997e18c..f73bf6bf 100644 --- a/pkg/test/headscale.go +++ b/pkg/test/headscale.go @@ -1,7 +1,6 @@ package test import ( - "context" _ "embed" "io" "log/slog" @@ -95,20 +94,3 @@ func ConnectVPNClient(t testing.TB, hostname, controllerURL, authkey string) { require.True(c, status.Self.Online) }, 10*time.Second, 50*time.Millisecond) } - -type tokenAuth struct { - token string -} - -func (t tokenAuth) GetRequestMetadata( - ctx context.Context, - _ ...string, -) (map[string]string, error) { - return map[string]string{ - "authorization": "Bearer " + t.token, - }, nil -} - -func (tokenAuth) RequireTransportSecurity() bool { - return false -} From 18d883ccc33add5b97fe32cecc658a5691f9befb Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Mon, 22 Dec 2025 09:34:31 +0100 Subject: [PATCH 10/18] Fix tests --- pkg/test/headscale.go | 5 +--- pkg/test/masterdata.go | 2 ++ pkg/test/rethinkdb.go | 55 ++++++++++++++++++++++++------------------ 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/pkg/test/headscale.go b/pkg/test/headscale.go index f73bf6bf..30aa8c2a 100644 --- a/pkg/test/headscale.go +++ b/pkg/test/headscale.go @@ -53,15 +53,12 @@ func StartHeadscale(t testing.TB) (headscalev1.HeadscaleServiceClient, string, s output, err := io.ReadAll(reader) require.NoError(t, err) apikey := strings.TrimSpace(string(output)) - t.Logf("apikey:%q\n", apikey) require.NoError(t, err) - endpoint, err = headscaleContainer.PortEndpoint(ctx, "50443/tcp", "") + endpoint, err := headscaleContainer.PortEndpoint(ctx, "50443/tcp", "") require.NoError(t, err) - t.Log(endpoint) controllerURL, err := headscaleContainer.PortEndpoint(ctx, "8080/tcp", "http") require.NoError(t, err) - t.Log(controllerURL) client, err := headscale.NewClient(headscale.Config{ Log: slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{})), diff --git a/pkg/test/masterdata.go b/pkg/test/masterdata.go index eb310e67..a6d26a93 100644 --- a/pkg/test/masterdata.go +++ b/pkg/test/masterdata.go @@ -12,6 +12,7 @@ import ( "github.com/metal-stack/masterdata-api/pkg/datastore" "github.com/metal-stack/masterdata-api/pkg/service" "github.com/stretchr/testify/require" + "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/modules/postgres" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -25,6 +26,7 @@ func StartMasterdataWithPostgres(t testing.TB, log *slog.Logger) (mdc.Client, *g "postgres:18-alpine", postgres.WithPassword("password"), postgres.BasicWaitStrategies(), + testcontainers.WithTmpfs(map[string]string{"/var/lib/postgresql": "rw"}), ) require.NoError(t, err) diff --git a/pkg/test/rethinkdb.go b/pkg/test/rethinkdb.go index 3b0ca437..ffb0b4d5 100644 --- a/pkg/test/rethinkdb.go +++ b/pkg/test/rethinkdb.go @@ -2,12 +2,15 @@ package test import ( "context" + "io" "log/slog" "strings" "sync" "testing" + "time" "github.com/metal-stack/metal-apiserver/pkg/db/generic" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go" tlog "github.com/testcontainers/testcontainers-go/log" @@ -18,40 +21,39 @@ import ( const rethinkDbImage = "rethinkdb:2.4.4-bookworm-slim" var ( - connectOpts r.ConnectOpts - endpoint string - closer func() - mtx sync.Mutex + connectOpts r.ConnectOpts + rethinkDbEndpoint string + closer func() + mtx sync.Mutex + rethinkdbContainer testcontainers.Container ) func StartRethink(t testing.TB, log *slog.Logger) (generic.Datastore, r.ConnectOpts, func()) { mtx.Lock() defer mtx.Unlock() - if endpoint == "" { + if rethinkDbEndpoint == "" { ctx := context.Background() - req := testcontainers.ContainerRequest{ - Image: rethinkDbImage, - ExposedPorts: []string{"8080/tcp", "28015/tcp"}, - Env: map[string]string{"RETHINKDB_PASSWORD": "rethink"}, - Tmpfs: map[string]string{"/data": "rw"}, - WaitingFor: wait.ForAll( - wait.ForListeningPort("28015/tcp"), + c, err := testcontainers.Run( + ctx, + rethinkDbImage, + testcontainers.WithExposedPorts("8080/tcp", "28015/tcp"), + testcontainers.WithTmpfs(map[string]string{"/data": "rw"}), + testcontainers.WithWaitStrategy( + wait.ForListeningPort("28015/tcp").WithStartupTimeout(time.Second*5), + wait.ForExposedPort(), ), - Cmd: []string{"rethinkdb", "--bind", "all", "--directory", "/data", "--initial-password", "rethink", "--io-threads", "500"}, - } - - c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ - ContainerRequest: req, - Started: true, - Logger: tlog.TestLogger(t), - }) + testcontainers.WithEnv(map[string]string{"RETHINKDB_PASSWORD": "rethink"}), + testcontainers.WithCmd("rethinkdb", "--bind", "all", "--directory", "/data", "--initial-password", "rethink", "--io-threads", "500"), + testcontainers.WithLogger(tlog.TestLogger(t)), + ) require.NoError(t, err) - endpoint, err = c.PortEndpoint(ctx, "28015/tcp", "") + rethinkDbEndpoint, err = c.PortEndpoint(ctx, "28015/tcp", "") require.NoError(t, err) + rethinkdbContainer = c closer = func() { // TODO: clean up database of this test @@ -61,7 +63,7 @@ func StartRethink(t testing.TB, log *slog.Logger) (generic.Datastore, r.ConnectO } connectOpts = r.ConnectOpts{ - Address: endpoint, + Address: rethinkDbEndpoint, Database: databaseNameFromT(t), Username: "admin", Password: "rethink", @@ -70,7 +72,14 @@ func StartRethink(t testing.TB, log *slog.Logger) (generic.Datastore, r.ConnectO } err := generic.Initialize(t.Context(), log, connectOpts, generic.AsnPoolRange(uint(1), uint(100)), generic.VrfPoolRange(uint(1), uint(100))) - require.NoError(t, err) + assert.NoError(t, err) + if err != nil { + reader, err := rethinkdbContainer.Logs(t.Context()) + require.NoError(t, err) + logs, err := io.ReadAll(reader) + require.NoError(t, err) + t.Log(string(logs)) + } ds, err := generic.New(log, connectOpts) require.NoError(t, err) From 88ff806379de29eec52e22676d0d44e593b32cc8 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Mon, 22 Dec 2025 09:44:51 +0100 Subject: [PATCH 11/18] fix --- pkg/test/rethinkdb.go | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/pkg/test/rethinkdb.go b/pkg/test/rethinkdb.go index ffb0b4d5..c08dc43d 100644 --- a/pkg/test/rethinkdb.go +++ b/pkg/test/rethinkdb.go @@ -2,7 +2,6 @@ package test import ( "context" - "io" "log/slog" "strings" "sync" @@ -10,7 +9,6 @@ import ( "time" "github.com/metal-stack/metal-apiserver/pkg/db/generic" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go" tlog "github.com/testcontainers/testcontainers-go/log" @@ -21,16 +19,15 @@ import ( const rethinkDbImage = "rethinkdb:2.4.4-bookworm-slim" var ( - connectOpts r.ConnectOpts - rethinkDbEndpoint string - closer func() - mtx sync.Mutex - rethinkdbContainer testcontainers.Container + rethinkDbConnectOpts r.ConnectOpts + rethinkDbEndpoint string + rethinkDbCloser func() + rethinkDbMtx sync.Mutex ) func StartRethink(t testing.TB, log *slog.Logger) (generic.Datastore, r.ConnectOpts, func()) { - mtx.Lock() - defer mtx.Unlock() + rethinkDbMtx.Lock() + defer rethinkDbMtx.Unlock() if rethinkDbEndpoint == "" { ctx := context.Background() @@ -53,8 +50,7 @@ func StartRethink(t testing.TB, log *slog.Logger) (generic.Datastore, r.ConnectO rethinkDbEndpoint, err = c.PortEndpoint(ctx, "28015/tcp", "") require.NoError(t, err) - rethinkdbContainer = c - closer = func() { + rethinkDbCloser = func() { // TODO: clean up database of this test // we do not terminate the container here because it's very complex with a shared ds @@ -62,7 +58,7 @@ func StartRethink(t testing.TB, log *slog.Logger) (generic.Datastore, r.ConnectO } } - connectOpts = r.ConnectOpts{ + rethinkDbConnectOpts = r.ConnectOpts{ Address: rethinkDbEndpoint, Database: databaseNameFromT(t), Username: "admin", @@ -71,20 +67,13 @@ func StartRethink(t testing.TB, log *slog.Logger) (generic.Datastore, r.ConnectO MaxOpen: 2000, } - err := generic.Initialize(t.Context(), log, connectOpts, generic.AsnPoolRange(uint(1), uint(100)), generic.VrfPoolRange(uint(1), uint(100))) - assert.NoError(t, err) - if err != nil { - reader, err := rethinkdbContainer.Logs(t.Context()) - require.NoError(t, err) - logs, err := io.ReadAll(reader) - require.NoError(t, err) - t.Log(string(logs)) - } + err := generic.Initialize(t.Context(), log, rethinkDbConnectOpts, generic.AsnPoolRange(uint(1), uint(100)), generic.VrfPoolRange(uint(1), uint(100))) + require.NoError(t, err) - ds, err := generic.New(log, connectOpts) + ds, err := generic.New(log, rethinkDbConnectOpts) require.NoError(t, err) - return ds, connectOpts, closer + return ds, rethinkDbConnectOpts, rethinkDbCloser } func databaseNameFromT(t testing.TB) string { From a2b4c712c1e2b04d837ef04169d81abd4df8495c Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Mon, 22 Dec 2025 10:09:24 +0100 Subject: [PATCH 12/18] Add default Policy --- pkg/service/vpn/admin/vpn-service.go | 27 +++++++++++++++ pkg/service/vpn/admin/vpn-service_test.go | 40 +++++++++++++++++++++++ pkg/test/headscale-config.yaml | 9 +++++ 3 files changed, 76 insertions(+) diff --git a/pkg/service/vpn/admin/vpn-service.go b/pkg/service/vpn/admin/vpn-service.go index 875dd4bd..062b0ac6 100644 --- a/pkg/service/vpn/admin/vpn-service.go +++ b/pkg/service/vpn/admin/vpn-service.go @@ -50,6 +50,9 @@ type VPNService interface { EvaluateVPNConnected(ctx context.Context) ([]*apiv2.Machine, error) // ControlPlaneAddress returns the address of headscale where tailscale clients must connect to ControlPlaneAddress() string + // SetDefaultPolicy stores a acl which allows communication between machines in the same project only + // Should be called on startup + SetDefaultPolicy() error } func New(c Config) VPNService { @@ -265,3 +268,27 @@ func (v *vpnService) EvaluateVPNConnected(ctx context.Context) ([]*apiv2.Machine return updatedMachines, nil } + +// This policy allows all users to access their own devices. +// It is suitable for many use cases where you want to +// allow users to access their own devices, but not other devices in the tailnet. +const defaultPolicy = `{ + "acls": [ + { + "action": "accept", + "src": ["autogroup:member"], + "dst": ["autogroup:self:*"] + } + ] + }` + +func (v *vpnService) SetDefaultPolicy() error { + resp, err := v.headscaleClient.SetPolicy(context.Background(), &headscalev1.SetPolicyRequest{ + Policy: defaultPolicy, + }) + if err != nil { + return err + } + v.log.Info("setdefaultpolicy", "policy stored", resp.Policy) + return nil +} diff --git a/pkg/service/vpn/admin/vpn-service_test.go b/pkg/service/vpn/admin/vpn-service_test.go index d0e316eb..408630a4 100644 --- a/pkg/service/vpn/admin/vpn-service_test.go +++ b/pkg/service/vpn/admin/vpn-service_test.go @@ -464,3 +464,43 @@ func Test_vpnService_EvaluateVPNConnected(t *testing.T) { }) } } + +func Test_vpnService_SetDefaultPolicy(t *testing.T) { + t.Parallel() + + log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) + ctx := t.Context() + headscaleClient, _, _, headscaleCloser := test.StartHeadscale(t) + defer headscaleCloser() + + _, err := headscaleClient.CreateUser(ctx, &v1.CreateUserRequest{ + Name: p1, + }) + require.NoError(t, err) + + tests := []struct { + name string + wantErr error + }{ + { + name: "set policy", + wantErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := &vpnService{ + log: log, + headscaleClient: headscaleClient, + } + err := v.SetDefaultPolicy() + if diff := cmp.Diff(err, tt.wantErr, errorutil.ConnectErrorComparer()); diff != "" { + t.Errorf("diff = %s", diff) + return + } + resp, err := v.headscaleClient.GetPolicy(t.Context(), &v1.GetPolicyRequest{}) + require.NoError(t, err) + require.Equal(t, defaultPolicy, resp.Policy) + }) + } +} diff --git a/pkg/test/headscale-config.yaml b/pkg/test/headscale-config.yaml index c1e09f74..d8e34ebf 100644 --- a/pkg/test/headscale-config.yaml +++ b/pkg/test/headscale-config.yaml @@ -78,6 +78,15 @@ log: # Output formatting for logs: text or json format: json +## Policy +# headscale supports Tailscale's ACL policies. +# Please have a look to their KB to better +# understand the concepts: https://tailscale.com/kb/1018/acls/ +policy: + # The mode can be "file" or "database" that defines + # where the ACL policies are stored and read from. + mode: database + database: # Database type. Available options: sqlite, postgres # Please note that using Postgres is highly discouraged as it is only supported for legacy reasons. From 81a04b08c02dafeb61d47d697af01c7812b35398 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Mon, 22 Dec 2025 10:12:50 +0100 Subject: [PATCH 13/18] Add default Policy --- pkg/service/vpn/admin/vpn-service_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/service/vpn/admin/vpn-service_test.go b/pkg/service/vpn/admin/vpn-service_test.go index 408630a4..a7222db7 100644 --- a/pkg/service/vpn/admin/vpn-service_test.go +++ b/pkg/service/vpn/admin/vpn-service_test.go @@ -500,7 +500,7 @@ func Test_vpnService_SetDefaultPolicy(t *testing.T) { } resp, err := v.headscaleClient.GetPolicy(t.Context(), &v1.GetPolicyRequest{}) require.NoError(t, err) - require.Equal(t, defaultPolicy, resp.Policy) + require.JSONEq(t, defaultPolicy, resp.Policy) }) } } From 31239fab9140914206031d784024d7d1d59927a7 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Mon, 22 Dec 2025 11:58:53 +0100 Subject: [PATCH 14/18] Reduce binary be 10Mb --- go.mod | 31 ---------- go.sum | 84 ---------------------------- pkg/service/vpn/admin/vpn-service.go | 5 +- 3 files changed, 3 insertions(+), 117 deletions(-) diff --git a/go.mod b/go.mod index d61da025..c9439230 100644 --- a/go.mod +++ b/go.mod @@ -92,7 +92,6 @@ require ( github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect - github.com/creachadair/mds v0.25.10 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dblohm7/wingoes v0.0.0-20240801171404-fc12d7c70140 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect @@ -102,18 +101,13 @@ require ( github.com/docker/docker v28.5.2+incompatible // indirect github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/ebitengine/purego v0.9.1 // indirect github.com/emicklei/go-restful-openapi/v2 v2.11.0 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/gaissmai/bart v0.18.0 // indirect - github.com/glebarez/go-sqlite v1.22.0 // indirect - github.com/glebarez/sqlite v1.11.0 // indirect github.com/go-chi/chi/v5 v5.2.3 // indirect - github.com/go-gormigrate/gormigrate/v2 v2.1.5 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // indirect github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect github.com/go-logr/logr v1.4.3 // indirect @@ -149,12 +143,6 @@ require ( github.com/hdevalence/ed25519consensus v0.2.0 // indirect github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0 // indirect github.com/illarion/gonotify/v3 v3.0.2 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/pgx/v5 v5.7.6 // indirect - github.com/jackc/puddle/v2 v2.2.2 // indirect - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jsimonetti/rtnetlink v1.4.1 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -169,8 +157,6 @@ require ( github.com/lopezator/migrator v0.3.1 // indirect github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect github.com/magiconair/properties v1.8.10 // indirect - github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect github.com/mdelapenya/tlscert v0.2.0 // indirect github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect @@ -191,12 +177,10 @@ require ( github.com/montanaflynn/stats v0.7.1 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/ncruces/go-strftime v1.0.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect @@ -205,29 +189,21 @@ require ( github.com/prometheus/common v0.67.4 // indirect github.com/prometheus/otlptranslator v1.0.0 // indirect github.com/prometheus/procfs v0.19.2 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/robfig/cron/v3 v3.0.1 // indirect - github.com/rs/zerolog v1.34.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/safchain/ethtool v0.3.0 // indirect - github.com/sagikazarmark/locafero v0.12.0 // indirect github.com/segmentio/asm v1.2.1 // indirect github.com/shirou/gopsutil/v4 v4.25.11 // indirect github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect - github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect - github.com/spf13/pflag v1.0.10 // indirect - github.com/spf13/viper v1.21.0 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect github.com/stretchr/objx v0.5.3 // indirect - github.com/subosito/gotenv v1.6.0 // indirect github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33 // indirect github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 // indirect github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect - github.com/tailscale/squibble v0.0.0-20251030164342-4d5df9caa993 // indirect github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect @@ -273,13 +249,6 @@ require ( gopkg.in/cenkalti/backoff.v2 v2.2.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gorm.io/driver/postgres v1.6.0 // indirect - gorm.io/gorm v1.31.0 // indirect gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 // indirect - modernc.org/libc v1.66.10 // indirect - modernc.org/mathutil v1.7.1 // indirect - modernc.org/memory v1.11.0 // indirect - modernc.org/sqlite v1.39.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect - zgo.at/zcache/v2 v2.4.1 // indirect ) diff --git a/go.sum b/go.sum index e9838779..eb8a54ef 100644 --- a/go.sum +++ b/go.sum @@ -111,15 +111,12 @@ github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNv github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= 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.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creachadair/mds v0.25.10 h1:9k9JB35D1xhOCFl0liBhagBBp8fWWkKZrA7UXsfoHtA= -github.com/creachadair/mds v0.25.10/go.mod h1:4hatI3hRM+qhzuAmqPRFvaBM8mONkS7nsLxkcuTYUIs= github.com/creachadair/taskgroup v0.13.2 h1:3KyqakBuFsm3KkXi/9XIb0QcA8tEzLHLgaoidf0MdVc= github.com/creachadair/taskgroup v0.13.2/go.mod h1:i3V1Zx7H8RjwljUEeUWYT30Lmb9poewSb2XI1yTwD0g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -147,8 +144,6 @@ github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pM 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= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -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= github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/emicklei/go-restful-openapi/v2 v2.11.0 h1:Ur+yGxoOH/7KRmcj/UoMFqC3VeNc9VOe+/XidumxTvk= @@ -161,22 +156,14 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo= github.com/gaissmai/bart v0.18.0/go.mod h1:JJzMAhNF5Rjo4SF4jWBrANuJfqY+FvsFhW7t1UZJ+XY= github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= -github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= -github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= -github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= -github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= -github.com/go-gormigrate/gormigrate/v2 v2.1.5 h1:1OyorA5LtdQw12cyJDEHuTrEV3GiXiIhS4/QTTa/SM8= -github.com/go-gormigrate/gormigrate/v2 v2.1.5/go.mod h1:mj9ekk/7CPF3VjopaFvWKN2v7fN3D9d3eEOAXRhi/+M= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I= @@ -246,7 +233,6 @@ github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737 h1:cf60tHxREO github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737/go.mod h1:MIS0jDzbU/vuM9MC4YnBITCv+RYuTRq8dJzmCrFsK9g= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg= github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -274,8 +260,6 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI= github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4= -github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d h1:KJIErDwbSHjnp/SGzE5ed8Aol7JsKiI5X7yWKAtzhM0= -github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -323,10 +307,6 @@ github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJBcYE71g= github.com/jellydator/ttlcache/v3 v3.1.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -390,13 +370,6 @@ github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= -github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI= @@ -456,8 +429,6 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= -github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -474,8 +445,6 @@ github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgr github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= -github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -501,8 +470,6 @@ github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4 github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/redis/go-redis/v9 v9.17.2 h1:P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI= github.com/redis/go-redis/v9 v9.17.2/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= -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/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8= @@ -511,15 +478,10 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= -github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= -github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0= github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs= -github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= -github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= @@ -529,14 +491,8 @@ github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1Tmu github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0= github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= -github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= -github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= -github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -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/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs= github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -556,8 +512,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ= github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4= github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4= @@ -572,8 +526,6 @@ github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 h1:uFsXVBE9Qr4 github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0= github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc h1:24heQPtnFR+yfntqhI3oAu9i27nEojcQ4NuBQOo5ZFA= github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc/go.mod h1:f93CXfllFsO9ZQVq+Zocb1Gp4G5Fz0b0rXHLOzt/Djc= -github.com/tailscale/squibble v0.0.0-20251030164342-4d5df9caa993 h1:FyiiAvDAxpB0DrW2GW3KOVfi3YFOtsQUEeFWbf55JJU= -github.com/tailscale/squibble v0.0.0-20251030164342-4d5df9caa993/go.mod h1:xJkMmR3t+thnUQhA3Q4m2VSlS5pcOq+CIjmU/xfKKx4= github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 h1:UBPHPtv8+nEAy2PD8RyAhOYvau1ek0HDJqLS/Pysi14= github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ= github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6 h1:l10Gi6w9jxvinoiq15g8OToDdASBni4CyJOdHY1Hr8M= @@ -722,11 +674,9 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -790,10 +740,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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= -gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4= -gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo= -gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY= -gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 h1:2gap+Kh/3F47cO6hAu3idFvsJ0ue6TRcEi2IUkv/F8k= @@ -802,39 +748,9 @@ honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I= honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= -modernc.org/cc/v4 v4.26.5 h1:xM3bX7Mve6G8K8b+T11ReenJOT+BmVqQj0FY5T4+5Y4= -modernc.org/cc/v4 v4.26.5/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.28.1 h1:wPKYn5EC/mYTqBO373jKjvX2n+3+aK7+sICCv4Fjy1A= -modernc.org/ccgo/v4 v4.28.1/go.mod h1:uD+4RnfrVgE6ec9NGguUNdhqzNIeeomeXf6CL0GTE5Q= -modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= -modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= -modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= -modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= -modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.66.10 h1:yZkb3YeLx4oynyR+iUsXsybsX4Ubx7MQlSYEw4yj59A= -modernc.org/libc v1.66.10/go.mod h1:8vGSEwvoUoltr4dlywvHqjtAqHBaw0j1jI7iFBTAr2I= -modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= -modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= -modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= -modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= -modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= -modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= -modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= -modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.39.1 h1:H+/wGFzuSCIEVCvXYVHX5RQglwhMOvtHSv+VtidL2r4= -modernc.org/sqlite v1.39.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE= -modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= -modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= -modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= tailscale.com v1.86.5 h1:yBtWFjuLYDmxVnfnvPbZNZcKADCYgNfMd0rUAOA9XCs= tailscale.com v1.86.5/go.mod h1:Lm8dnzU2i/Emw15r6sl3FRNp/liSQ/nYw6ZSQvIdZ1M= -zgo.at/zcache/v2 v2.4.1 h1:Dfjoi8yI0Uq7NCc4lo2kaQJJmp9Mijo21gef+oJstbY= -zgo.at/zcache/v2 v2.4.1/go.mod h1:gyCeoLVo01QjDZynjime8xUGHHMbsLiPyUTBpDGd4Gk= -zombiezen.com/go/postgrestest v1.0.1 h1:aXoADQAJmZDU3+xilYVut0pHhgc0sF8ZspPW9gFNwP4= -zombiezen.com/go/postgrestest v1.0.1/go.mod h1:marlZezr+k2oSJrvXHnZUs1olHqpE9czlz8ZYkVxliQ= diff --git a/pkg/service/vpn/admin/vpn-service.go b/pkg/service/vpn/admin/vpn-service.go index 062b0ac6..394c84a8 100644 --- a/pkg/service/vpn/admin/vpn-service.go +++ b/pkg/service/vpn/admin/vpn-service.go @@ -10,7 +10,6 @@ import ( "time" headscalev1 "github.com/juanfont/headscale/gen/go/headscale/v1" - headscaledb "github.com/juanfont/headscale/hscontrol/db" "google.golang.org/protobuf/types/known/timestamppb" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" @@ -110,7 +109,9 @@ func (v *vpnService) CreateUser(ctx context.Context, name string) (*headscalev1. }) // TODO check if this is still like this if err != nil { - if strings.Contains(err.Error(), headscaledb.ErrUserExists.Error()) || strings.Contains(err.Error(), "UNIQUE constraint failed") { + // Importing the error from "github.com/juanfont/headscale/hscontrol/db" would pull + // the whole headscale dependencies and the resulting binary would be ~10Mb bigger + if strings.Contains(err.Error(), "user already exists") || strings.Contains(err.Error(), "UNIQUE constraint failed") { return nil, errorutil.NewConflict(err) } return nil, err From 4a14bab08a639f24e25a8d9cce771703215b7dca Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Mon, 22 Dec 2025 12:00:57 +0100 Subject: [PATCH 15/18] Reduce binary be 10Mb --- go.mod | 34 +++++----------------------------- go.sum | 23 +++++++++++------------ 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/go.mod b/go.mod index c9439230..b580e48b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/metal-stack/metal-apiserver -go 1.25 +go 1.25.5 require ( buf.build/go/protovalidate v1.1.0 @@ -48,7 +48,7 @@ require ( google.golang.org/grpc v1.77.0 google.golang.org/protobuf v1.36.11 gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.2 - tailscale.com v1.86.5 + tailscale.com v1.92.4 ) replace github.com/markbates/goth => github.com/metal-stack/goth v0.1.0 @@ -64,20 +64,6 @@ require ( github.com/akutz/memconn v0.1.0 // indirect github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect - github.com/aws/aws-sdk-go-v2 v1.36.0 // indirect - github.com/aws/aws-sdk-go-v2/config v1.29.5 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.58 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12 // indirect - github.com/aws/aws-sdk-go-v2/service/ssm v1.45.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.13 // indirect - github.com/aws/smithy-go v1.22.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -86,17 +72,16 @@ require ( github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v1.0.0-rc.2 // indirect - github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect github.com/coreos/go-oidc/v3 v3.17.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect + github.com/creachadair/msync v0.7.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dblohm7/wingoes v0.0.0-20240801171404-fc12d7c70140 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/docker v28.5.2+incompatible // indirect github.com/docker/go-connections v0.6.0 // indirect @@ -136,14 +121,11 @@ require ( github.com/golang/snappy v1.0.0 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/cel-go v0.26.1 // indirect - github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect github.com/hdevalence/ed25519consensus v0.2.0 // indirect github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0 // indirect - github.com/illarion/gonotify/v3 v3.0.2 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jsimonetti/rtnetlink v1.4.1 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.2 // indirect @@ -158,11 +140,8 @@ require ( github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect github.com/magiconair/properties v1.8.10 // indirect github.com/mdelapenya/tlscert v0.2.0 // indirect - github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect - github.com/mdlayher/sdnotify v1.0.0 // indirect github.com/mdlayher/socket v0.5.0 // indirect - github.com/miekg/dns v1.1.58 // indirect github.com/minio/minlz v1.0.1 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect @@ -181,6 +160,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pires/go-proxyproto v0.8.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect @@ -202,13 +182,11 @@ require ( github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33 // indirect - github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 // indirect github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect github.com/tklauser/numcpus v0.11.0 // indirect - github.com/vishvananda/netns v0.0.5 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.2.0 // indirect @@ -234,14 +212,12 @@ require ( go.yaml.in/yaml/v3 v3.0.4 // indirect go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect golang.org/x/crypto v0.46.0 // indirect - golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect - golang.org/x/mod v0.31.0 // indirect + golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect golang.org/x/net v0.48.0 // indirect golang.org/x/sys v0.39.0 // indirect golang.org/x/term v0.38.0 // indirect golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.40.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect diff --git a/go.sum b/go.sum index eb8a54ef..69804e4c 100644 --- a/go.sum +++ b/go.sum @@ -117,6 +117,8 @@ github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GK 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.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creachadair/msync v0.7.1 h1:SeZmuEBXQPe5GqV/C94ER7QIZPwtvFbeQiykzt/7uho= +github.com/creachadair/msync v0.7.1/go.mod h1:8CcFlLsSujfHE5wWm19uUBLHIPDAUr6LXDwneVMO008= github.com/creachadair/taskgroup v0.13.2 h1:3KyqakBuFsm3KkXi/9XIb0QcA8tEzLHLgaoidf0MdVc= github.com/creachadair/taskgroup v0.13.2/go.mod h1:i3V1Zx7H8RjwljUEeUWYT30Lmb9poewSb2XI1yTwD0g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -281,6 +283,7 @@ github.com/hibiken/asynq v0.25.1/go.mod h1:pazWNOLBu0FEynQRBvHA26qdIKRSmfdIfUm4H github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0 h1:nHoRIX8iXob3Y2kdt9KsjyIb7iApSvb3vgsd93xb5Ow= github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0/go.mod h1:c1tRKs5Tx7E2+uHGSyyncziFjvGpgv4H2HrqXeUQ/Uk= +github.com/illarion/gonotify v1.0.1 h1:F1d+0Fgbq/sDWjj/r66ekjDG+IDeecQKUFH4wNwsoio= github.com/illarion/gonotify/v3 v3.0.2 h1:O7S6vcopHexutmpObkeWsnzMJt/r1hONIEogeVNmJMk= github.com/illarion/gonotify/v3 v3.0.2/go.mod h1:HWGPdPe817GfvY3w7cx6zkbzNZfi3QjcBm/wgVvEL1U= github.com/insomniacslk/dhcp v0.0.0-20240204152450-ca2dc33955c1 h1:L3pm9Kf2G6gJVYawz2SrI5QnV1wzHYbqmKnSHHXJAb8= @@ -309,8 +312,6 @@ github.com/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJ github.com/jellydator/ttlcache/v3 v3.1.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -447,6 +448,8 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0= +github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= @@ -556,7 +559,6 @@ github.com/valkey-io/valkey-go v1.0.59 h1:W67Z0UY+Qqk3k8NKkFCFlM3X4yQUniixl7dSJA github.com/valkey-io/valkey-go v1.0.59/go.mod h1:bHmwjIEOrGq/ubOJfh5uMRs7Xj6mV3mQ/ZXUbmqpjqY= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -629,8 +631,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= -golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w= @@ -664,8 +666,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -734,7 +734,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 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.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -744,13 +743,13 @@ gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 h1:2gap+Kh/3F47cO6hAu3idFvsJ0ue6TRcEi2IUkv/F8k= gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM= -honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I= -honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs= +honnef.co/go/tools v0.7.0-0.dev.0.20251022135355-8273271481d0 h1:5SXjd4ET5dYijLaf0O3aOenC0Z4ZafIWSpjUzsQaNho= +honnef.co/go/tools v0.7.0-0.dev.0.20251022135355-8273271481d0/go.mod h1:EPDDhEZqVHhWuPI5zPAsjU0U7v9xNIWjoOVyZ5ZcniQ= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= -tailscale.com v1.86.5 h1:yBtWFjuLYDmxVnfnvPbZNZcKADCYgNfMd0rUAOA9XCs= -tailscale.com v1.86.5/go.mod h1:Lm8dnzU2i/Emw15r6sl3FRNp/liSQ/nYw6ZSQvIdZ1M= +tailscale.com v1.92.4 h1:agmk0My9BJZRVplQj6Sf+3k/BpsoXuf1IA0qeWdBKE0= +tailscale.com v1.92.4/go.mod h1:jzTfKDd6XNNSNoX+Q9INIMpMU5rfZ9g8ojcAoMKi5w0= From fb6d9c6a822f29716cd7768cdec6a8684c69a515 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Wed, 24 Dec 2025 08:45:51 +0100 Subject: [PATCH 16/18] lesser logs --- go.mod | 2 +- go.sum | 4 ++-- pkg/service/vpn/admin/vpn-service.go | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index b580e48b..380bc2d7 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,7 @@ require ( go4.org/netipx v0.0.0-20231129151722-fdeea329fbba golang.org/x/oauth2 v0.34.0 golang.org/x/sync v0.19.0 - google.golang.org/grpc v1.77.0 + google.golang.org/grpc v1.78.0 google.golang.org/protobuf v1.36.11 gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.2 tailscale.com v1.92.4 diff --git a/go.sum b/go.sum index 69804e4c..68174b28 100644 --- a/go.sum +++ b/go.sum @@ -712,8 +712,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1: google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= -google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= -google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= diff --git a/pkg/service/vpn/admin/vpn-service.go b/pkg/service/vpn/admin/vpn-service.go index 394c84a8..59c274f3 100644 --- a/pkg/service/vpn/admin/vpn-service.go +++ b/pkg/service/vpn/admin/vpn-service.go @@ -188,7 +188,6 @@ func (v *vpnService) getNode(ctx context.Context, machineID, projectID string) ( return nil, fmt.Errorf("failed to list nodes: %w", err) } - v.log.Debug("getNode", "nodes", resp.Nodes) for _, m := range resp.Nodes { if m.Name == machineID { return m, nil @@ -217,8 +216,6 @@ func (v *vpnService) EvaluateVPNConnected(ctx context.Context) ([]*apiv2.Machine return nil, err } - v.log.Debug("evaluated vpn connected", "machines", ms, "nodes", listNodesResp.Nodes) - var ( errs []error updatedMachines []*apiv2.Machine From 2a6ce7b24589c413b30042944d61dc5d6f14e5e3 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Sat, 27 Dec 2025 08:26:42 +0100 Subject: [PATCH 17/18] Remove tailscale from main depedency and reduce binary by 16Mb --- go.mod | 62 +++++----- go.sum | 133 +++++++++++----------- pkg/request/tokenpermissions_test.go | 3 +- pkg/service/vpn/admin/vpn-service.go | 15 ++- pkg/service/vpn/admin/vpn-service_test.go | 39 +++++-- pkg/test/headscale.go | 16 --- 6 files changed, 134 insertions(+), 134 deletions(-) diff --git a/go.mod b/go.mod index 380bc2d7..7916ab40 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( connectrpc.com/connect v1.19.1 connectrpc.com/grpchealth v1.4.0 connectrpc.com/grpcreflect v1.3.0 - connectrpc.com/otelconnect v0.8.0 + connectrpc.com/otelconnect v0.9.0 connectrpc.com/validate v0.6.0 github.com/Masterminds/semver/v3 v3.4.0 github.com/alicebob/miniredis/v2 v2.35.0 @@ -22,11 +22,11 @@ require ( github.com/jmoiron/sqlx v1.4.0 github.com/juanfont/headscale v0.27.1 github.com/klauspost/connect-compress/v2 v2.1.0 - github.com/lestrrat-go/jwx/v3 v3.0.12 + github.com/lestrrat-go/jwx/v3 v3.0.13 github.com/looplab/fsm v1.0.3 github.com/markbates/goth v1.82.0 - github.com/metal-stack/api v0.0.37-0.20251221083840-3f9177e3233f - github.com/metal-stack/go-ipam v1.14.13 + github.com/metal-stack/api v0.0.37 + github.com/metal-stack/go-ipam v1.14.14 github.com/metal-stack/masterdata-api v0.13.0 github.com/metal-stack/metal-lib v0.23.5 github.com/metal-stack/security v0.9.5 @@ -40,15 +40,15 @@ require ( github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 github.com/testcontainers/testcontainers-go/modules/valkey v0.40.0 github.com/urfave/cli/v2 v2.27.7 - go.opentelemetry.io/otel/exporters/prometheus v0.60.0 - go.opentelemetry.io/otel/sdk/metric v1.38.0 + go.opentelemetry.io/otel/exporters/prometheus v0.61.0 + go.opentelemetry.io/otel/sdk/metric v1.39.0 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba golang.org/x/oauth2 v0.34.0 golang.org/x/sync v0.19.0 google.golang.org/grpc v1.78.0 google.golang.org/protobuf v1.36.11 gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.2 - tailscale.com v1.92.4 + tailscale.com v1.92.5 ) replace github.com/markbates/goth => github.com/metal-stack/goth v0.1.0 @@ -122,11 +122,11 @@ require ( github.com/google/btree v1.1.2 // indirect github.com/google/cel-go v0.26.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect github.com/hdevalence/ed25519consensus v0.2.0 // indirect github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0 // indirect - github.com/jsimonetti/rtnetlink v1.4.1 // indirect + github.com/jsimonetti/rtnetlink v1.4.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.2 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect @@ -140,12 +140,12 @@ require ( github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect github.com/magiconair/properties v1.8.10 // indirect github.com/mdelapenya/tlscert v0.2.0 // indirect - github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect - github.com/mdlayher/socket v0.5.0 // indirect + github.com/mdlayher/netlink v1.8.0 // indirect + github.com/mdlayher/socket v0.5.1 // indirect github.com/minio/minlz v1.0.1 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/moby/go-archive v0.1.0 // indirect + github.com/moby/go-archive v0.2.0 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.6.0 // indirect github.com/moby/sys/user v0.4.0 // indirect @@ -154,7 +154,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.7.1 // indirect - github.com/morikuni/aec v1.0.0 // indirect + github.com/morikuni/aec v1.1.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect @@ -164,16 +164,16 @@ require ( github.com/pkg/errors v0.9.1 // 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-community/pro-bing v0.4.0 // indirect + github.com/prometheus-community/pro-bing v0.7.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/otlptranslator v1.0.0 // indirect github.com/prometheus/procfs v0.19.2 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/safchain/ethtool v0.3.0 // indirect + github.com/safchain/ethtool v0.7.0 // indirect github.com/segmentio/asm v1.2.1 // indirect - github.com/shirou/gopsutil/v4 v4.25.11 // indirect + github.com/shirou/gopsutil/v4 v4.25.12 // indirect github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect github.com/spf13/cast v1.10.0 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect @@ -195,33 +195,33 @@ require ( github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect github.com/yuin/gopher-lua v1.1.1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - go.etcd.io/etcd/api/v3 v3.6.6 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.6.6 // indirect - go.etcd.io/etcd/client/v3 v3.6.6 // indirect + go.etcd.io/etcd/api/v3 v3.6.7 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.7 // indirect + go.etcd.io/etcd/client/v3 v3.6.7 // indirect go.mongodb.org/mongo-driver v1.17.6 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/otel/sdk v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect - golang.org/x/crypto v0.46.0 // indirect + golang.org/x/crypto v0.47.0 // indirect golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect golang.org/x/net v0.48.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/term v0.38.0 // indirect - golang.org/x/text v0.32.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/term v0.39.0 // indirect + golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.14.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect gopkg.in/cenkalti/backoff.v2 v2.2.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 68174b28..b47c2293 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ connectrpc.com/grpchealth v1.4.0 h1:MJC96JLelARPgZTiRF9KRfY/2N9OcoQvF2EWX07v2IE= connectrpc.com/grpchealth v1.4.0/go.mod h1:WhW6m1EzTmq3Ky1FE8EfkIpSDc6TfUx2M2KqZO3ts/Q= connectrpc.com/grpcreflect v1.3.0 h1:Y4V+ACf8/vOb1XOc251Qun7jMB75gCUNw6llvB9csXc= connectrpc.com/grpcreflect v1.3.0/go.mod h1:nfloOtCS8VUQOQ1+GTdFzVg2CJo4ZGaat8JIovCtDYs= -connectrpc.com/otelconnect v0.8.0 h1:a4qrN4H8aEE2jAoCxheZYYfEjXMgVPyL9OzPQLBEFXU= -connectrpc.com/otelconnect v0.8.0/go.mod h1:AEkVLjCPXra+ObGFCOClcJkNjS7zPaQSqvO0lCyjfZc= +connectrpc.com/otelconnect v0.9.0 h1:NggB3pzRC3pukQWaYbRHJulxuXvmCKCKkQ9hbrHAWoA= +connectrpc.com/otelconnect v0.9.0/go.mod h1:AEkVLjCPXra+ObGFCOClcJkNjS7zPaQSqvO0lCyjfZc= connectrpc.com/validate v0.6.0 h1:DcrgDKt2ZScrUs/d/mh9itD2yeEa0UbBBa+i0mwzx+4= connectrpc.com/validate v0.6.0/go.mod h1:ihrpI+8gVbLH1fvVWJL1I3j0CfWnF8P/90LsmluRiZs= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= @@ -272,8 +272,8 @@ github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzq github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 h1:B+8ClL/kCQkRiU82d9xajRPKYMrB7E0MbtzWVi1K4ns= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3/go.mod h1:NbCUVmiS4foBGBHOYlCT25+YmGpJ32dZPi75pGEUpj4= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 h1:kEISI/Gx67NzH3nJxAmY/dGac80kKZgZt134u7Y/k1s= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4/go.mod h1:6Nz966r3vQYCqIzWsuEl9d7cf7mRhtDmm++sOxlnfxI= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= @@ -315,8 +315,8 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jsimonetti/rtnetlink v1.4.1 h1:JfD4jthWBqZMEffc5RjgmlzpYttAVw1sdnmiNaPO3hE= -github.com/jsimonetti/rtnetlink v1.4.1/go.mod h1:xJjT7t59UIZ62GLZbv6PLLo8VFrostJMPBAheR6OM8w= +github.com/jsimonetti/rtnetlink v1.4.2 h1:Df9w9TZ3npHTyDn0Ev9e1uzmN2odmXd0QX+J5GTEn90= +github.com/jsimonetti/rtnetlink v1.4.2/go.mod h1:92s6LJdE+1iOrw+F2/RO7LYI2Qd8pPpFNNUYW06gcoM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/juanfont/headscale v0.27.1 h1:BSvxiQX3GBgLUrAO3fpYnftnBUAUqgLkZVpS4G+b82c= @@ -354,8 +354,8 @@ github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZ github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= github.com/lestrrat-go/httprc/v3 v3.0.2 h1:7u4HUaD0NQbf2/n5+fyp+T10hNCsAnwKfqn4A4Baif0= github.com/lestrrat-go/httprc/v3 v3.0.2/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0= -github.com/lestrrat-go/jwx/v3 v3.0.12 h1:p25r68Y4KrbBdYjIsQweYxq794CtGCzcrc5dGzJIRjg= -github.com/lestrrat-go/jwx/v3 v3.0.12/go.mod h1:HiUSaNmMLXgZ08OmGBaPVvoZQgJVOQphSrGr5zMamS8= +github.com/lestrrat-go/jwx/v3 v3.0.13 h1:AdHKiPIYeCSnOJtvdpipPg/0SuFh9rdkN+HF3O0VdSk= +github.com/lestrrat-go/jwx/v3 v3.0.13/go.mod h1:2m0PV1A9tM4b/jVLMx8rh6rBl7F6WGb3EG2hufN9OQU= github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss= github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= @@ -377,16 +377,16 @@ github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5L github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o= github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= -github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg= -github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o= +github.com/mdlayher/netlink v1.8.0 h1:e7XNIYJKD7hUct3Px04RuIGJbBxy1/c4nX7D5YyvvlM= +github.com/mdlayher/netlink v1.8.0/go.mod h1:UhgKXUlDQhzb09DrCl2GuRNEglHmhYoWAHid9HK3594= github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ3c= github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= -github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI= -github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI= -github.com/metal-stack/api v0.0.37-0.20251221083840-3f9177e3233f h1:/nhmgT8oWkokbPx3yjegukn66s9aheGFqkDUUMe3s/o= -github.com/metal-stack/api v0.0.37-0.20251221083840-3f9177e3233f/go.mod h1:lVDIha/gViLpYuJi+OhQIQCeh6XYdzGxrtbtJTJ94eI= -github.com/metal-stack/go-ipam v1.14.13 h1:/W5/MDBX5EU18xNDjlBvV6JjQ1Ot12dO2WxLvV6S8vc= -github.com/metal-stack/go-ipam v1.14.13/go.mod h1:eif3UGUFP7CWJdrgLIOjhVM3G2K19GN8lhCgPVfvLDs= +github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= +github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= +github.com/metal-stack/api v0.0.37 h1:dHH4d+XgyjogdF8gvKt7UUUbCnKmfnUhicNi7zfzQbc= +github.com/metal-stack/api v0.0.37/go.mod h1:lVDIha/gViLpYuJi+OhQIQCeh6XYdzGxrtbtJTJ94eI= +github.com/metal-stack/go-ipam v1.14.14 h1:5qb2ZRqhenqi+jeuPkva9kroB44Q92vs/JhhNywwcI4= +github.com/metal-stack/go-ipam v1.14.14/go.mod h1:lV1pA5vruYjzUCL4dF+lF5AAw5jZod9ZACvCCNyVdEU= github.com/metal-stack/goth v0.1.0 h1:sdadAH9QG+xAjLNKAJq8+esfXct6icTs58juoR4BKrQ= github.com/metal-stack/goth v0.1.0/go.mod h1:FNz3T5lydfi+ls1O3adXgN9Xmn4sn/SZE4t+Sswl+Uc= github.com/metal-stack/masterdata-api v0.13.0 h1:1AxnsiWiTMstjMsphZ0wMFT7aW3QQhAMumXnQ81PtHk= @@ -405,8 +405,8 @@ github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= -github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= +github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8= +github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= @@ -426,8 +426,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ= +github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= @@ -459,14 +459,14 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4= -github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4= +github.com/prometheus-community/pro-bing v0.7.0 h1:KFYFbxC2f2Fp6c+TyxbCOEarf7rbnzr9Gw8eIb0RfZA= +github.com/prometheus-community/pro-bing v0.7.0/go.mod h1:Moob9dvlY50Bfq6i88xIwfyw7xLFHH69LUgx9n5zqCE= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= -github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos= github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= @@ -483,14 +483,14 @@ github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0= -github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs= +github.com/safchain/ethtool v0.7.0 h1:rlJzfDetsVvT61uz8x1YIcFn12akMfuPulHtZjtb7Is= +github.com/safchain/ethtool v0.7.0/go.mod h1:MenQKEjXdfkjD3mp2QdCk8B/hwvkrlOTm/FD4gTpFxQ= github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= -github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAXZILTY= -github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= +github.com/shirou/gopsutil/v4 v4.25.12 h1:e7PvW/0RmJ8p8vPGJH4jvNkOyLmbkXgXW4m6ZPic6CY= +github.com/shirou/gopsutil/v4 v4.25.12/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0= github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -557,8 +557,8 @@ github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= github.com/valkey-io/valkey-go v1.0.59 h1:W67Z0UY+Qqk3k8NKkFCFlM3X4yQUniixl7dSJAch2Qo= github.com/valkey-io/valkey-go v1.0.59/go.mod h1:bHmwjIEOrGq/ubOJfh5uMRs7Xj6mV3mQ/ZXUbmqpjqY= -github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= -github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +github.com/valyala/fastjson v1.6.7 h1:ZE4tRy0CIkh+qDc5McjatheGX2czdn8slQjomexVpBM= +github.com/valyala/fastjson v1.6.7/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -580,34 +580,34 @@ github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.etcd.io/etcd/api/v3 v3.6.6 h1:mcaMp3+7JawWv69p6QShYWS8cIWUOl32bFLb6qf8pOQ= -go.etcd.io/etcd/api/v3 v3.6.6/go.mod h1:f/om26iXl2wSkcTA1zGQv8reJRSLVdoEBsi4JdfMrx4= -go.etcd.io/etcd/client/pkg/v3 v3.6.6 h1:uoqgzSOv2H9KlIF5O1Lsd8sW+eMLuV6wzE3q5GJGQNs= -go.etcd.io/etcd/client/pkg/v3 v3.6.6/go.mod h1:YngfUVmvsvOJ2rRgStIyHsKtOt9SZI2aBJrZiWJhCbI= -go.etcd.io/etcd/client/v3 v3.6.6 h1:G5z1wMf5B9SNexoxOHUGBaULurOZPIgGPsW6CN492ec= -go.etcd.io/etcd/client/v3 v3.6.6/go.mod h1:36Qv6baQ07znPR3+n7t+Rk5VHEzVYPvFfGmfF4wBHV8= +go.etcd.io/etcd/api/v3 v3.6.7 h1:7BNJ2gQmc3DNM+9cRkv7KkGQDayElg8x3X+tFDYS+E0= +go.etcd.io/etcd/api/v3 v3.6.7/go.mod h1:xJ81TLj9hxrYYEDmXTeKURMeY3qEDN24hqe+q7KhbnI= +go.etcd.io/etcd/client/pkg/v3 v3.6.7 h1:vvzgyozz46q+TyeGBuFzVuI53/yd133CHceNb/AhBVs= +go.etcd.io/etcd/client/pkg/v3 v3.6.7/go.mod h1:2IVulJ3FZ/czIGl9T4lMF1uxzrhRahLqe+hSgy+Kh7Q= +go.etcd.io/etcd/client/v3 v3.6.7 h1:9WqA5RpIBtdMxAy1ukXLAdtg2pAxNqW5NUoO2wQrE6U= +go.etcd.io/etcd/client/v3 v3.6.7/go.mod h1:2XfROY56AXnUqGsvl+6k29wrwsSbEh1lAouQB1vHpeE= go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss= go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= 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.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= -go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= -go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= -go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= -go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= -go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= -go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= -go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= -go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= +go.opentelemetry.io/otel/exporters/prometheus v0.61.0 h1:cCyZS4dr67d30uDyh8etKM2QyDsQ4zC9ds3bdbrVoD0= +go.opentelemetry.io/otel/exporters/prometheus v0.61.0/go.mod h1:iivMuj3xpR2DkUrUya3TPS/Z9h3dz7h01GxU+fQBRNg= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -629,8 +629,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= @@ -676,19 +676,18 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= -golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -708,10 +707,10 @@ golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= -google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b h1:uA40e2M6fYRBf0+8uN5mLlqUtV192iiksiICIBkYJ1E= +google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:Xa7le7qx2vmqB/SzWUBa7KdMjpdpAHlh5QCSnjessQk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= @@ -751,5 +750,5 @@ sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= -tailscale.com v1.92.4 h1:agmk0My9BJZRVplQj6Sf+3k/BpsoXuf1IA0qeWdBKE0= -tailscale.com v1.92.4/go.mod h1:jzTfKDd6XNNSNoX+Q9INIMpMU5rfZ9g8ojcAoMKi5w0= +tailscale.com v1.92.5 h1:h88HqtGk8jd9umF7l6m/8+QK69dY9IVMIlkNK9XYpvQ= +tailscale.com v1.92.5/go.mod h1:jzTfKDd6XNNSNoX+Q9INIMpMU5rfZ9g8ojcAoMKi5w0= diff --git a/pkg/request/tokenpermissions_test.go b/pkg/request/tokenpermissions_test.go index 3560bd2e..118b450b 100644 --- a/pkg/request/tokenpermissions_test.go +++ b/pkg/request/tokenpermissions_test.go @@ -81,7 +81,7 @@ func Test_getTokenPermissions(t *testing.T) { "/metalstack.admin.v2.TokenService/Create": {"*": {}}, "/metalstack.admin.v2.TokenService/List": {"*": {}}, "/metalstack.admin.v2.TokenService/Revoke": {"*": {}}, - "/metalstack.admin.v2.VPNService/Authkey": {"*": {}}, + "/metalstack.admin.v2.VPNService/AuthKey": {"*": {}}, "/metalstack.admin.v2.VPNService/ListNodes": {"*": {}}, "/metalstack.api.v2.FilesystemService/Get": {"*": {}}, "/metalstack.api.v2.FilesystemService/List": {"*": {}}, @@ -176,6 +176,7 @@ func Test_getTokenPermissions(t *testing.T) { "/metalstack.admin.v2.SwitchService/List": {"*": {}}, "/metalstack.admin.v2.TenantService/List": {"*": {}}, "/metalstack.admin.v2.TokenService/List": {"*": {}}, + "/metalstack.admin.v2.VPNService/ListNodes": {"*": {}}, "/metalstack.api.v2.FilesystemService/Get": {"*": {}}, "/metalstack.api.v2.FilesystemService/List": {"*": {}}, "/metalstack.api.v2.FilesystemService/Match": {"*": {}}, diff --git a/pkg/service/vpn/admin/vpn-service.go b/pkg/service/vpn/admin/vpn-service.go index 59c274f3..94df4dc6 100644 --- a/pkg/service/vpn/admin/vpn-service.go +++ b/pkg/service/vpn/admin/vpn-service.go @@ -17,7 +17,6 @@ import ( apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/metal-stack/metal-apiserver/pkg/errorutil" "github.com/metal-stack/metal-apiserver/pkg/repository" - "github.com/metal-stack/metal-lib/pkg/pointer" ) const defaultExpiration = time.Hour @@ -63,7 +62,7 @@ func New(c Config) VPNService { } } -func (v *vpnService) Authkey(ctx context.Context, req *adminv2.VPNServiceAuthkeyRequest) (*adminv2.VPNServiceAuthkeyResponse, error) { +func (v *vpnService) AuthKey(ctx context.Context, req *adminv2.VPNServiceAuthKeyRequest) (*adminv2.VPNServiceAuthKeyResponse, error) { _, err := v.repo.Project(req.Project).Get(ctx, req.Project) if err != nil { return nil, err @@ -93,9 +92,9 @@ func (v *vpnService) Authkey(ctx context.Context, req *adminv2.VPNServiceAuthkey return nil, errorutil.Convert(err) } - return &adminv2.VPNServiceAuthkeyResponse{ + return &adminv2.VPNServiceAuthKeyResponse{ Address: v.headscaleControlplaneAddress, - Authkey: key.PreAuthKey.Key, + AuthKey: key.PreAuthKey.Key, }, nil } @@ -138,8 +137,8 @@ func (v *vpnService) DeleteNode(ctx context.Context, machineID string, projectID // ListNodes implements [VPNService]. func (v *vpnService) ListNodes(ctx context.Context, req *adminv2.VPNServiceListNodesRequest) (*adminv2.VPNServiceListNodesResponse, error) { lnr := &headscalev1.ListNodesRequest{} - if req.User != nil { - lnr.User = *req.User + if req.Project != nil { + lnr.User = *req.Project } resp, err := v.headscaleClient.ListNodes(ctx, lnr) if err != nil { @@ -150,7 +149,7 @@ func (v *vpnService) ListNodes(ctx context.Context, req *adminv2.VPNServiceListN vpnNodes = append(vpnNodes, &apiv2.VPNNode{ Id: node.Id, Name: node.Name, - User: &node.User.Name, + Project: node.User.Name, IpAddresses: node.IpAddresses, LastSeen: node.LastSeen, Online: node.Online, @@ -230,7 +229,7 @@ func (v *vpnService) EvaluateVPNConnected(ctx context.Context) ([]*apiv2.Machine return false } - if pointer.SafeDeref(node.User) != m.Allocation.Project { + if node.Project != m.Allocation.Project { return false } diff --git a/pkg/service/vpn/admin/vpn-service_test.go b/pkg/service/vpn/admin/vpn-service_test.go index a7222db7..c1822f70 100644 --- a/pkg/service/vpn/admin/vpn-service_test.go +++ b/pkg/service/vpn/admin/vpn-service_test.go @@ -15,10 +15,12 @@ import ( v1 "github.com/juanfont/headscale/gen/go/headscale/v1" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" + "tailscale.com/tsnet" "github.com/metal-stack/metal-apiserver/pkg/db/metal" "github.com/metal-stack/metal-apiserver/pkg/errorutil" "github.com/metal-stack/metal-apiserver/pkg/test" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/durationpb" @@ -34,7 +36,7 @@ var ( p2 = "00000000-0000-0000-0000-000000000002" ) -func Test_vpnService_Authkey(t *testing.T) { +func Test_vpnService_AuthKey(t *testing.T) { t.Parallel() log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) @@ -61,19 +63,19 @@ func Test_vpnService_Authkey(t *testing.T) { }) tests := []struct { name string - req *adminv2.VPNServiceAuthkeyRequest - want *adminv2.VPNServiceAuthkeyResponse + req *adminv2.VPNServiceAuthKeyRequest + want *adminv2.VPNServiceAuthKeyResponse wantErr error }{ { name: "create a new authkey", - req: &adminv2.VPNServiceAuthkeyRequest{ + req: &adminv2.VPNServiceAuthKeyRequest{ Project: p0, Ephemeral: false, Expires: durationpb.New(time.Hour), }, - want: &adminv2.VPNServiceAuthkeyResponse{ + want: &adminv2.VPNServiceAuthKeyResponse{ Address: endpoint, }, }, @@ -87,18 +89,18 @@ func Test_vpnService_Authkey(t *testing.T) { headscaleControlplaneAddress: endpoint, } - got, gotErr := v.Authkey(t.Context(), tt.req) + got, gotErr := v.AuthKey(t.Context(), tt.req) if gotErr != nil { if tt.wantErr == nil { - t.Errorf("Authkey() failed: %v", gotErr) + t.Errorf("AuthKey() failed: %v", gotErr) } return } if tt.wantErr != nil { - t.Fatal("Authkey() succeeded unexpectedly") + t.Fatal("AuthKey() succeeded unexpectedly") } require.Equal(t, tt.want.Address, got.Address) - require.Greater(t, len(got.Authkey), 10) + require.Greater(t, len(got.AuthKey), 10) }) } } @@ -122,7 +124,7 @@ func Test_vpnService_DeleteNode(t *testing.T) { }) require.NoError(t, err) - test.ConnectVPNClient(t, m1, controllerURL, key.PreAuthKey.Key) + connectVPNClient(t, m1, controllerURL, key.PreAuthKey.Key) defer func() { headscaleCloser() @@ -425,7 +427,7 @@ func Test_vpnService_EvaluateVPNConnected(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { for _, n := range tt.nodesToCreate { - test.ConnectVPNClient(t, n, controllerURL, key.PreAuthKey.Key) + connectVPNClient(t, n, controllerURL, key.PreAuthKey.Key) } test.CreateMachines(t, testStore, tt.machinesToCreate) @@ -504,3 +506,18 @@ func Test_vpnService_SetDefaultPolicy(t *testing.T) { }) } } + +func connectVPNClient(t testing.TB, hostname, controllerURL, authkey string) { + s := &tsnet.Server{ + Hostname: hostname, + ControlURL: controllerURL, + AuthKey: authkey, + } + lc, err := s.LocalClient() + require.NoError(t, err) + require.EventuallyWithT(t, func(c *assert.CollectT) { + status, err := lc.Status(t.Context()) + require.NoError(c, err) + require.True(c, status.Self.Online) + }, 10*time.Second, 50*time.Millisecond) +} diff --git a/pkg/test/headscale.go b/pkg/test/headscale.go index 30aa8c2a..4370c50c 100644 --- a/pkg/test/headscale.go +++ b/pkg/test/headscale.go @@ -11,7 +11,6 @@ import ( headscalev1 "github.com/juanfont/headscale/gen/go/headscale/v1" "github.com/metal-stack/metal-apiserver/pkg/headscale" - "tailscale.com/tsnet" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -76,18 +75,3 @@ func StartHeadscale(t testing.TB) (headscalev1.HeadscaleServiceClient, string, s return client, endpoint, controllerURL, closer } - -func ConnectVPNClient(t testing.TB, hostname, controllerURL, authkey string) { - s := &tsnet.Server{ - Hostname: hostname, - ControlURL: controllerURL, - AuthKey: authkey, - } - lc, err := s.LocalClient() - require.NoError(t, err) - require.EventuallyWithT(t, func(c *assert.CollectT) { - status, err := lc.Status(t.Context()) - require.NoError(c, err) - require.True(c, status.Self.Online) - }, 10*time.Second, 50*time.Millisecond) -} From cdc930363c2038aa3242fc9da663a85a34795e87 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Fri, 16 Jan 2026 14:00:52 +0100 Subject: [PATCH 18/18] review findings --- go.mod | 33 +++++++--- go.sum | 76 ++++++++++++----------- pkg/db/metal/nic.go | 2 +- pkg/db/metal/switch_test.go | 2 +- pkg/request/tokenpermissions_test.go | 12 ++-- pkg/service/vpn/admin/vpn-service.go | 27 ++++---- pkg/service/vpn/admin/vpn-service_test.go | 23 +++---- 7 files changed, 97 insertions(+), 78 deletions(-) diff --git a/go.mod b/go.mod index b80ab0dd..d7efbca1 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/lestrrat-go/jwx/v3 v3.0.13 github.com/looplab/fsm v1.0.3 github.com/markbates/goth v1.82.0 - github.com/metal-stack/api v0.0.38 + github.com/metal-stack/api v0.0.39 github.com/metal-stack/go-ipam v1.14.14 github.com/metal-stack/masterdata-api v0.13.0 github.com/metal-stack/metal-lib v0.23.5 @@ -48,7 +48,7 @@ require ( google.golang.org/grpc v1.78.0 google.golang.org/protobuf v1.36.11 gopkg.in/rethinkdb/rethinkdb-go.v6 v6.2.2 - tailscale.com v1.92.5 + tailscale.com v1.94.0 ) replace github.com/markbates/goth => github.com/metal-stack/goth v0.1.0 @@ -64,6 +64,19 @@ require ( github.com/akutz/memconn v0.1.0 // indirect github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.41.0 // indirect + github.com/aws/aws-sdk-go-v2/config v1.29.5 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.58 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect + github.com/aws/smithy-go v1.24.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -90,7 +103,7 @@ require ( github.com/emicklei/go-restful-openapi/v2 v2.11.0 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/gaissmai/bart v0.18.0 // indirect github.com/go-chi/chi/v5 v5.2.4 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // indirect @@ -114,22 +127,23 @@ require ( github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/goccy/go-json v0.10.5 // indirect - github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect + github.com/godbus/dbus/v5 v5.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v1.0.0 // indirect - github.com/google/btree v1.1.2 // indirect + github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 // indirect github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect github.com/hdevalence/ed25519consensus v0.2.0 // indirect + github.com/huin/goupnp v1.3.0 // indirect github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0 // indirect github.com/jackc/pgtype v1.14.4 // indirect github.com/jackc/pgx/v4 v4.18.3 // indirect github.com/jackc/pgx/v5 v5.8.0 // indirect - github.com/jsimonetti/rtnetlink v1.4.1 // indirect + github.com/jsimonetti/rtnetlink v1.4.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.3 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect @@ -155,7 +169,7 @@ require ( github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/montanaflynn/stats v0.7.1 // indirect github.com/morikuni/aec v1.1.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -183,7 +197,6 @@ require ( github.com/stretchr/objx v0.5.3 // indirect github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect - github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33 // indirect github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect @@ -216,7 +229,7 @@ require ( go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect golang.org/x/crypto v0.47.0 // indirect golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect - golang.org/x/net v0.48.0 // indirect + golang.org/x/net v0.49.0 // indirect golang.org/x/sys v0.40.0 // indirect golang.org/x/term v0.39.0 // indirect golang.org/x/text v0.33.0 // indirect diff --git a/go.sum b/go.sum index 821345a2..4c316d39 100644 --- a/go.sum +++ b/go.sum @@ -48,34 +48,36 @@ github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYW github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/avast/retry-go/v4 v4.7.0 h1:yjDs35SlGvKwRNSykujfjdMxMhMQQM0TnIjJaHB+Zio= github.com/avast/retry-go/v4 v4.7.0/go.mod h1:ZMPDa3sY2bKgpLtap9JRUgk2yTAba7cgiFhqxY2Sg6Q= -github.com/aws/aws-sdk-go-v2 v1.36.0 h1:b1wM5CcE65Ujwn565qcwgtOTT1aT4ADOHHgglKjG7fk= -github.com/aws/aws-sdk-go-v2 v1.36.0/go.mod h1:5PMILGVKiW32oDzjj6RU52yrNrDPUHcbZQYr1sM7qmM= +github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4= +github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= github.com/aws/aws-sdk-go-v2/config v1.29.5 h1:4lS2IB+wwkj5J43Tq/AwvnscBerBJtQQ6YS7puzCI1k= github.com/aws/aws-sdk-go-v2/config v1.29.5/go.mod h1:SNzldMlDVbN6nWxM7XsUiNXPSa1LWlqiXtvh/1PrJGg= github.com/aws/aws-sdk-go-v2/credentials v1.17.58 h1:/d7FUpAPU8Lf2KUdjniQvfNdlMID0Sd9pS23FJ3SS9Y= github.com/aws/aws-sdk-go-v2/credentials v1.17.58/go.mod h1:aVYW33Ow10CyMQGFgC0ptMRIqJWvJ4nxZb0sUiuQT/A= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 h1:7lOW8NUwE9UZekS1DYoiPdVAqZ6A+LheHWb+mHbNOq8= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27/go.mod h1:w1BASFIPOPUae7AgaH4SbjNbfdkxuggLyGfNFTn8ITY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31 h1:lWm9ucLSRFiI4dQQafLrEOmEDGry3Swrz0BIRdiHJqQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31/go.mod h1:Huu6GG0YTfbPphQkDSo4dEGmQRTKb9k9G7RdtyQWxuI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31 h1:ACxDklUKKXb48+eg5ROZXi1vDgfMyfIA/WyvqHcHI0o= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31/go.mod h1:yadnfsDwqXeVaohbGc/RaD287PuyRw2wugkh5ZL2J6k= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12 h1:O+8vD2rGjfihBewr5bT+QUfYUHIxCVgG61LHoT59shM= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12/go.mod h1:usVdWJaosa66NMvmCrr08NcWDBRv4E6+YFG2pUdw1Lk= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM= github.com/aws/aws-sdk-go-v2/service/ssm v1.45.0 h1:IOdss+igJDFdic9w3WKwxGCmHqUxydvIhJOm9LJ32Dk= github.com/aws/aws-sdk-go-v2/service/ssm v1.45.0/go.mod h1:Q7XIWsMo0JcMpI/6TGD6XXcXcV1DbTj6e9BKNntIMIM= github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 h1:c5WJ3iHz7rLIgArznb3JCSQT3uUMiz9DLZhIX+1G8ok= github.com/aws/aws-sdk-go-v2/service/sso v1.24.14/go.mod h1:+JJQTxB6N4niArC14YNtxcQtwEqzS3o9Z32n7q33Rfs= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 h1:f1L/JtUkVODD+k1+IiSJUUv8A++2qVr+Xvb3xWXETMU= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13/go.mod h1:tvqlFoja8/s0o+UruA1Nrezo/df0PzdunMDDurUfg6U= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.13 h1:3LXNnmtH3TURctC23hnC0p/39Q5gre3FI7BNOiDcVWc= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.13/go.mod h1:7Yn+p66q/jt38qMoVfNvjbm3D89mGBnkwDcijgtih8w= -github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= -github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk= +github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= +github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= +github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02 h1:bXAPYSbdYbS5VTy92NIUbeDI1qyggi+JYh5op9IFlcQ= +github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0= @@ -95,8 +97,8 @@ github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1x github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= -github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= +github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= +github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= @@ -138,6 +140,8 @@ github.com/dblohm7/wingoes v0.0.0-20240801171404-fc12d7c70140 h1:g4XyYZ0ed3hBOZP github.com/dblohm7/wingoes v0.0.0-20240801171404-fc12d7c70140/go.mod h1:SUxUaAK/0UG5lYyZR1L1nC4AaYYvSSYTWQSH3FPcxKU= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= +github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc h1:8WFBn63wegobsYAX0YjD+8suexZDga5CctH4CCTx2+8= +github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= @@ -164,8 +168,8 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo= github.com/gaissmai/bart v0.18.0/go.mod h1:JJzMAhNF5Rjo4SF4jWBrANuJfqY+FvsFhW7t1UZJ+XY= github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= @@ -244,23 +248,23 @@ github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737 h1:cf60tHxREO github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737/go.mod h1:MIS0jDzbU/vuM9MC4YnBITCv+RYuTRq8dJzmCrFsK9g= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg= -github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU= +github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= +github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 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/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/cel-go v0.26.1 h1:iPbVVEdkhTX++hpe3lzSk7D3G3QSYqLGoHOcEio+UXQ= github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -292,6 +296,8 @@ github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3s github.com/hibiken/asynq v0.25.1 h1:phj028N0nm15n8O2ims+IvJ2gz4k2auvermngh9JhTw= github.com/hibiken/asynq v0.25.1/go.mod h1:pazWNOLBu0FEynQRBvHA26qdIKRSmfdIfUm4HdsLmXg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0 h1:nHoRIX8iXob3Y2kdt9KsjyIb7iApSvb3vgsd93xb5Ow= github.com/icza/dyno v0.0.0-20230330125955-09f820a8d9c0/go.mod h1:c1tRKs5Tx7E2+uHGSyyncziFjvGpgv4H2HrqXeUQ/Uk= github.com/illarion/gonotify v1.0.1 h1:F1d+0Fgbq/sDWjj/r66ekjDG+IDeecQKUFH4wNwsoio= @@ -363,8 +369,8 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jsimonetti/rtnetlink v1.4.1 h1:JfD4jthWBqZMEffc5RjgmlzpYttAVw1sdnmiNaPO3hE= -github.com/jsimonetti/rtnetlink v1.4.1/go.mod h1:xJjT7t59UIZ62GLZbv6PLLo8VFrostJMPBAheR6OM8w= +github.com/jsimonetti/rtnetlink v1.4.2 h1:Df9w9TZ3npHTyDn0Ev9e1uzmN2odmXd0QX+J5GTEn90= +github.com/jsimonetti/rtnetlink v1.4.2/go.mod h1:92s6LJdE+1iOrw+F2/RO7LYI2Qd8pPpFNNUYW06gcoM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/juanfont/headscale v0.27.1 h1:BSvxiQX3GBgLUrAO3fpYnftnBUAUqgLkZVpS4G+b82c= @@ -443,8 +449,8 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/metal-stack/api v0.0.38 h1:FKIX7bQiOSrS8QrbUH22gNueZYdDJgCUXEAKM1H9otQ= -github.com/metal-stack/api v0.0.38/go.mod h1:lVDIha/gViLpYuJi+OhQIQCeh6XYdzGxrtbtJTJ94eI= +github.com/metal-stack/api v0.0.39 h1:qSr3zOI7DBRb3oKiske70y+msCU7lxN5PPuSB+q8zUI= +github.com/metal-stack/api v0.0.39/go.mod h1:+/lG2mf3UZjfieogBlU/gLt1DVvZ/ZQ1v2kmhvHnPRc= github.com/metal-stack/go-ipam v1.14.14 h1:5qb2ZRqhenqi+jeuPkva9kroB44Q92vs/JhhNywwcI4= github.com/metal-stack/go-ipam v1.14.14/go.mod h1:lV1pA5vruYjzUCL4dF+lF5AAw5jZod9ZACvCCNyVdEU= github.com/metal-stack/goth v0.1.0 h1:sdadAH9QG+xAjLNKAJq8+esfXct6icTs58juoR4BKrQ= @@ -482,8 +488,9 @@ github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFL 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= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ= @@ -592,8 +599,6 @@ github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8 github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55/go.mod h1:4k4QO+dQ3R5FofL+SanAUZe+/QfeK0+OIuwDIRu2vSg= github.com/tailscale/golang-x-crypto v0.0.0-20250404221719-a5573b049869 h1:SRL6irQkKGQKKLzvQP/ke/2ZuB7Py5+XuqtOgSj+iMM= github.com/tailscale/golang-x-crypto v0.0.0-20250404221719-a5573b049869/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ= -github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 h1:4chzWmimtJPxRs2O36yuGRW3f9SYV+bMTTvMBI0EKio= -github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8= github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33 h1:idh63uw+gsG05HwjZsAENCG4KZfyvjK03bpjxa5qRRk= github.com/tailscale/hujson v0.0.0-20250226034555-ec1d1c113d33/go.mod h1:EbW0wDK/qEUYI0A5bqq0C2kF8JTQwWONmGDBbzsxxHo= github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 h1:uFsXVBE9Qr4ZoF094vE6iYTLDl0qCiKzYXlL6UeWObU= @@ -749,8 +754,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -782,7 +787,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -884,5 +888,5 @@ sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= -tailscale.com v1.92.5 h1:h88HqtGk8jd9umF7l6m/8+QK69dY9IVMIlkNK9XYpvQ= -tailscale.com v1.92.5/go.mod h1:jzTfKDd6XNNSNoX+Q9INIMpMU5rfZ9g8ojcAoMKi5w0= +tailscale.com v1.94.0 h1:5oW3SF35aU9ekHDhP2J4CHewnA2NxE7SRilDB2pVjaA= +tailscale.com v1.94.0/go.mod h1:gLnVrEOP32GWvroaAHHGhjSGMPJ1i4DvqNwEg+Yuov4= diff --git a/pkg/db/metal/nic.go b/pkg/db/metal/nic.go index fb166d88..be84714b 100644 --- a/pkg/db/metal/nic.go +++ b/pkg/db/metal/nic.go @@ -31,7 +31,7 @@ const ( BGPStateActive = BGPState("active") BGPStateOpenSent = BGPState("open-sent") BGPStateOpenConfirm = BGPState("open-confirm") - BGPStateEstablished = BGPState("established") + BGPStateEstablished = BGPState("Established") ) const ( diff --git a/pkg/db/metal/switch_test.go b/pkg/db/metal/switch_test.go index 09870ae2..a6c89561 100644 --- a/pkg/db/metal/switch_test.go +++ b/pkg/db/metal/switch_test.go @@ -17,7 +17,7 @@ func TestToReplaceMode(t *testing.T) { name: "unspecified", mode: apiv2.SwitchReplaceMode_SWITCH_REPLACE_MODE_UNSPECIFIED, want: "", - wantErr: true, + wantErr: false, }, { name: "valid", diff --git a/pkg/request/tokenpermissions_test.go b/pkg/request/tokenpermissions_test.go index 0de056e5..40b8e45b 100644 --- a/pkg/request/tokenpermissions_test.go +++ b/pkg/request/tokenpermissions_test.go @@ -147,6 +147,7 @@ func Test_getTokenPermissions(t *testing.T) { "/metalstack.api.v2.UserService/Get": {"*": {}}, "/metalstack.api.v2.VersionService/Get": {"*": {}}, "/metalstack.infra.v2.BMCService/UpdateBMCInfo": {"*": {}}, + "/metalstack.infra.v2.BMCService/WaitForMachineEvent": {"*": {}}, "/metalstack.infra.v2.EventService/Send": {"*": {}}, "/metalstack.infra.v2.SwitchService/Get": {"*": {}}, "/metalstack.infra.v2.SwitchService/Heartbeat": {"*": {}}, @@ -228,11 +229,12 @@ func Test_getTokenPermissions(t *testing.T) { InfraRole: apiv2.InfraRole_INFRA_ROLE_EDITOR.Enum(), }, want: tokenPermissions{ - "/metalstack.infra.v2.BMCService/UpdateBMCInfo": {"*": {}}, - "/metalstack.infra.v2.EventService/Send": {"*": {}}, - "/metalstack.infra.v2.SwitchService/Get": {"*": {}}, - "/metalstack.infra.v2.SwitchService/Heartbeat": {"*": {}}, - "/metalstack.infra.v2.SwitchService/Register": {"*": {}}, + "/metalstack.infra.v2.BMCService/UpdateBMCInfo": {"*": {}}, + "/metalstack.infra.v2.BMCService/WaitForMachineEvent": {"*": {}}, + "/metalstack.infra.v2.EventService/Send": {"*": {}}, + "/metalstack.infra.v2.SwitchService/Get": {"*": {}}, + "/metalstack.infra.v2.SwitchService/Heartbeat": {"*": {}}, + "/metalstack.infra.v2.SwitchService/Register": {"*": {}}, }, }, { diff --git a/pkg/service/vpn/admin/vpn-service.go b/pkg/service/vpn/admin/vpn-service.go index 94df4dc6..19574dfb 100644 --- a/pkg/service/vpn/admin/vpn-service.go +++ b/pkg/service/vpn/admin/vpn-service.go @@ -10,6 +10,7 @@ import ( "time" headscalev1 "github.com/juanfont/headscale/gen/go/headscale/v1" + "github.com/samber/lo" "google.golang.org/protobuf/types/known/timestamppb" adminv2 "github.com/metal-stack/api/go/metalstack/admin/v2" @@ -50,12 +51,12 @@ type VPNService interface { ControlPlaneAddress() string // SetDefaultPolicy stores a acl which allows communication between machines in the same project only // Should be called on startup - SetDefaultPolicy() error + SetDefaultPolicy(ctx context.Context) error } func New(c Config) VPNService { return &vpnService{ - log: c.Log, + log: c.Log.WithGroup("vpnService"), repo: c.Repo, headscaleClient: c.HeadscaleClient, headscaleControlplaneAddress: c.HeadscaleControlplaneAddress, @@ -63,6 +64,8 @@ func New(c Config) VPNService { } func (v *vpnService) AuthKey(ctx context.Context, req *adminv2.VPNServiceAuthKeyRequest) (*adminv2.VPNServiceAuthKeyResponse, error) { + v.log.Debug("authkey", "req", req) + _, err := v.repo.Project(req.Project).Get(ctx, req.Project) if err != nil { return nil, err @@ -103,6 +106,7 @@ func (v *vpnService) ControlPlaneAddress() string { } func (v *vpnService) CreateUser(ctx context.Context, name string) (*headscalev1.User, error) { + v.log.Debug("createUser", "name", name) resp, err := v.headscaleClient.CreateUser(ctx, &headscalev1.CreateUserRequest{ Name: name, }) @@ -119,6 +123,7 @@ func (v *vpnService) CreateUser(ctx context.Context, name string) (*headscalev1. } func (v *vpnService) DeleteNode(ctx context.Context, machineID string, projectID string) (*headscalev1.Node, error) { + v.log.Debug("deleteNode", "machine", machineID, "project", projectID) machine, err := v.getNode(ctx, machineID, projectID) if err != nil { return nil, err @@ -136,13 +141,14 @@ func (v *vpnService) DeleteNode(ctx context.Context, machineID string, projectID // ListNodes implements [VPNService]. func (v *vpnService) ListNodes(ctx context.Context, req *adminv2.VPNServiceListNodesRequest) (*adminv2.VPNServiceListNodesResponse, error) { + v.log.Debug("listnodes", "req", req) lnr := &headscalev1.ListNodesRequest{} if req.Project != nil { lnr.User = *req.Project } resp, err := v.headscaleClient.ListNodes(ctx, lnr) if err != nil { - return nil, fmt.Errorf("failed to list machines: %w", err) + return nil, fmt.Errorf("failed to list nodes: %w", err) } var vpnNodes []*apiv2.VPNNode for _, node := range resp.Nodes { @@ -207,7 +213,7 @@ func (v *vpnService) EvaluateVPNConnected(ctx context.Context) ([]*apiv2.Machine return nil, err } - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) + ctx, cancel := context.WithTimeout(ctx, 1*time.Minute) defer cancel() listNodesResp, err := v.ListNodes(ctx, &adminv2.VPNServiceListNodesRequest{}) @@ -224,7 +230,7 @@ func (v *vpnService) EvaluateVPNConnected(ctx context.Context) ([]*apiv2.Machine continue } - index := slices.IndexFunc(listNodesResp.Nodes, func(node *apiv2.VPNNode) bool { + node, ok := lo.Find(listNodesResp.Nodes, func(node *apiv2.VPNNode) bool { if node.Name != m.Uuid { return false } @@ -235,13 +241,12 @@ func (v *vpnService) EvaluateVPNConnected(ctx context.Context) ([]*apiv2.Machine return true }) - - if index < 0 { + if !ok { continue } - connected := listNodesResp.Nodes[index].Online - ips := listNodesResp.Nodes[index].IpAddresses + connected := node.Online + ips := node.IpAddresses if m.Allocation.Vpn.Connected == connected && slices.Equal(m.Allocation.Vpn.Ips, ips) { v.log.Info("not updating vpn because already up-to-date", "machine", m.Uuid, "connected", connected, "ips", ips) @@ -279,8 +284,8 @@ const defaultPolicy = `{ ] }` -func (v *vpnService) SetDefaultPolicy() error { - resp, err := v.headscaleClient.SetPolicy(context.Background(), &headscalev1.SetPolicyRequest{ +func (v *vpnService) SetDefaultPolicy(ctx context.Context) error { + resp, err := v.headscaleClient.SetPolicy(ctx, &headscalev1.SetPolicyRequest{ Policy: defaultPolicy, }) if err != nil { diff --git a/pkg/service/vpn/admin/vpn-service_test.go b/pkg/service/vpn/admin/vpn-service_test.go index c1822f70..327b42c4 100644 --- a/pkg/service/vpn/admin/vpn-service_test.go +++ b/pkg/service/vpn/admin/vpn-service_test.go @@ -89,18 +89,13 @@ func Test_vpnService_AuthKey(t *testing.T) { headscaleControlplaneAddress: endpoint, } - got, gotErr := v.AuthKey(t.Context(), tt.req) - if gotErr != nil { - if tt.wantErr == nil { - t.Errorf("AuthKey() failed: %v", gotErr) - } + got, err := v.AuthKey(t.Context(), tt.req) + if diff := cmp.Diff(err, tt.wantErr, errorutil.ConnectErrorComparer()); diff != "" { + t.Errorf("diff = %s", diff) return } - if tt.wantErr != nil { - t.Fatal("AuthKey() succeeded unexpectedly") - } require.Equal(t, tt.want.Address, got.Address) - require.Greater(t, len(got.AuthKey), 10) + require.NotEmpty(t, got.AuthKey) }) } } @@ -258,19 +253,19 @@ func Test_vpnService_userExists(t *testing.T) { name string username string want *v1.User - want2 bool + exists bool }{ { name: "get existing user", username: p1, want: &v1.User{Name: p1}, - want2: true, + exists: true, }, { name: "get non existing user", username: p2, want: nil, - want2: false, + exists: false, }, } for _, tt := range tests { @@ -280,7 +275,7 @@ func Test_vpnService_userExists(t *testing.T) { headscaleClient: headscaleClient, } got, got2 := v.userExists(context.Background(), tt.username) - if diff := cmp.Diff(got2, tt.want2); diff != "" { + if diff := cmp.Diff(got2, tt.exists); diff != "" { t.Errorf("diff = %s", diff) return } @@ -495,7 +490,7 @@ func Test_vpnService_SetDefaultPolicy(t *testing.T) { log: log, headscaleClient: headscaleClient, } - err := v.SetDefaultPolicy() + err := v.SetDefaultPolicy(ctx) if diff := cmp.Diff(err, tt.wantErr, errorutil.ConnectErrorComparer()); diff != "" { t.Errorf("diff = %s", diff) return