mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-01 06:36:39 +00:00
Compare commits
10 Commits
v0.67.1
...
feat/resel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a2b88a008 | ||
|
|
dedb7e51e9 | ||
|
|
b7c58dfdfb | ||
|
|
d185b68fe1 | ||
|
|
49757e99e2 | ||
|
|
daf7f41d69 | ||
|
|
7abf730d77 | ||
|
|
ec96c5ecaf | ||
|
|
7e1cce4b9f | ||
|
|
7be8752a00 |
4
.github/workflows/wasm-build-validation.yml
vendored
4
.github/workflows/wasm-build-validation.yml
vendored
@@ -61,8 +61,8 @@ jobs:
|
|||||||
|
|
||||||
echo "Size: ${SIZE} bytes (${SIZE_MB} MB)"
|
echo "Size: ${SIZE} bytes (${SIZE_MB} MB)"
|
||||||
|
|
||||||
if [ ${SIZE} -gt 57671680 ]; then
|
if [ ${SIZE} -gt 58720256 ]; then
|
||||||
echo "Wasm binary size (${SIZE_MB}MB) exceeds 55MB limit!"
|
echo "Wasm binary size (${SIZE_MB}MB) exceeds 56MB limit!"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
41
go.mod
41
go.mod
@@ -17,13 +17,13 @@ require (
|
|||||||
github.com/spf13/cobra v1.10.1
|
github.com/spf13/cobra v1.10.1
|
||||||
github.com/spf13/pflag v1.0.9
|
github.com/spf13/pflag v1.0.9
|
||||||
github.com/vishvananda/netlink v1.3.1
|
github.com/vishvananda/netlink v1.3.1
|
||||||
golang.org/x/crypto v0.46.0
|
golang.org/x/crypto v0.48.0
|
||||||
golang.org/x/sys v0.39.0
|
golang.org/x/sys v0.41.0
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1
|
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||||
golang.zx2c4.com/wireguard/windows v0.5.3
|
golang.zx2c4.com/wireguard/windows v0.5.3
|
||||||
google.golang.org/grpc v1.77.0
|
google.golang.org/grpc v1.79.3
|
||||||
google.golang.org/protobuf v1.36.10
|
google.golang.org/protobuf v1.36.11
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -101,21 +101,21 @@ require (
|
|||||||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||||
github.com/yusufpapurcu/wmi v1.2.4
|
github.com/yusufpapurcu/wmi v1.2.4
|
||||||
github.com/zcalusic/sysinfo v1.1.3
|
github.com/zcalusic/sysinfo v1.1.3
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0
|
||||||
go.opentelemetry.io/otel v1.38.0
|
go.opentelemetry.io/otel v1.42.0
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.48.0
|
go.opentelemetry.io/otel/exporters/prometheus v0.64.0
|
||||||
go.opentelemetry.io/otel/metric v1.38.0
|
go.opentelemetry.io/otel/metric v1.42.0
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0
|
go.opentelemetry.io/otel/sdk/metric v1.42.0
|
||||||
go.uber.org/mock v0.5.2
|
go.uber.org/mock v0.5.2
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
goauthentik.io/api/v3 v3.2023051.3
|
goauthentik.io/api/v3 v3.2023051.3
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
||||||
golang.org/x/mobile v0.0.0-20251113184115-a159579294ab
|
golang.org/x/mobile v0.0.0-20251113184115-a159579294ab
|
||||||
golang.org/x/mod v0.30.0
|
golang.org/x/mod v0.32.0
|
||||||
golang.org/x/net v0.47.0
|
golang.org/x/net v0.51.0
|
||||||
golang.org/x/oauth2 v0.34.0
|
golang.org/x/oauth2 v0.34.0
|
||||||
golang.org/x/sync v0.19.0
|
golang.org/x/sync v0.19.0
|
||||||
golang.org/x/term v0.38.0
|
golang.org/x/term v0.40.0
|
||||||
golang.org/x/time v0.14.0
|
golang.org/x/time v0.14.0
|
||||||
google.golang.org/api v0.257.0
|
google.golang.org/api v0.257.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
@@ -249,8 +249,9 @@ require (
|
|||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
github.com/prometheus/client_model v0.6.2 // indirect
|
github.com/prometheus/client_model v0.6.2 // indirect
|
||||||
github.com/prometheus/common v0.66.1 // indirect
|
github.com/prometheus/common v0.67.5 // indirect
|
||||||
github.com/prometheus/procfs v0.16.1 // indirect
|
github.com/prometheus/otlptranslator v1.0.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.19.2 // indirect
|
||||||
github.com/russellhaering/goxmldsig v1.5.0 // indirect
|
github.com/russellhaering/goxmldsig v1.5.0 // indirect
|
||||||
github.com/rymdport/portal v0.4.2 // indirect
|
github.com/rymdport/portal v0.4.2 // indirect
|
||||||
github.com/shirou/gopsutil/v4 v4.25.1 // indirect
|
github.com/shirou/gopsutil/v4 v4.25.1 // indirect
|
||||||
@@ -269,15 +270,15 @@ require (
|
|||||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.42.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
go.opentelemetry.io/otel/trace v1.42.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||||
golang.org/x/image v0.33.0 // indirect
|
golang.org/x/image v0.33.0 // indirect
|
||||||
golang.org/x/text v0.32.0 // indirect
|
golang.org/x/text v0.34.0 // indirect
|
||||||
golang.org/x/tools v0.39.0 // indirect
|
golang.org/x/tools v0.41.0 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
86
go.sum
86
go.sum
@@ -487,10 +487,12 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h
|
|||||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
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 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||||
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
|
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
|
||||||
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
|
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos=
|
||||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=
|
||||||
|
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
|
||||||
|
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
|
||||||
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
|
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
|
||||||
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
|
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
|
||||||
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||||
@@ -603,26 +605,26 @@ github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
|||||||
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
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/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 h1:yI1/OhfEPy7J9eoa6Sj051C7n5dvpj0QX8g4sRchg04=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0/go.mod h1:NoUCKYWK+3ecatC4HjkRktREheMeEtrXoQxrqYFeHSc=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
|
||||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
|
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 v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.48.0 h1:sBQe3VNGUjY9IKWQC6z2lNqa5iGbDSxhs60ABwK4y0s=
|
go.opentelemetry.io/otel/exporters/prometheus v0.64.0 h1:g0LRDXMX/G1SEZtK8zl8Chm4K6GBwRkjPKE36LxiTYs=
|
||||||
go.opentelemetry.io/otel/exporters/prometheus v0.48.0/go.mod h1:DtrbMzoZWwQHyrQmCfLam5DZbnmorsGbOtTbYHycU5o=
|
go.opentelemetry.io/otel/exporters/prometheus v0.64.0/go.mod h1:UrgcjnarfdlBDP3GjDIJWe6HTprwSazNjwsI+Ru6hro=
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=
|
||||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo=
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
|
||||||
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
@@ -633,8 +635,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||||
goauthentik.io/api/v3 v3.2023051.3 h1:NebAhD/TeTWNo/9X3/Uj+rM5fG1HaiLOlKTNLQv9Qq4=
|
goauthentik.io/api/v3 v3.2023051.3 h1:NebAhD/TeTWNo/9X3/Uj+rM5fG1HaiLOlKTNLQv9Qq4=
|
||||||
goauthentik.io/api/v3 v3.2023051.3/go.mod h1:nYECml4jGbp/541hj8GcylKQG1gVBsKppHy4+7G8u4U=
|
goauthentik.io/api/v3 v3.2023051.3/go.mod h1:nYECml4jGbp/541hj8GcylKQG1gVBsKppHy4+7G8u4U=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
@@ -648,8 +650,8 @@ golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1m
|
|||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||||
golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ=
|
golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ=
|
||||||
@@ -666,8 +668,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
|
||||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
@@ -686,8 +688,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
|||||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||||
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
||||||
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
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/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||||
@@ -738,8 +740,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|||||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@@ -752,8 +754,8 @@ golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
|||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||||
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
|
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
||||||
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@@ -765,8 +767,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
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/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@@ -780,8 +782,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
|
||||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -799,12 +801,12 @@ google.golang.org/api v0.257.0/go.mod h1:4eJrr+vbVaZSqs7vovFd1Jb/A6ml6iw2e6FBYf3
|
|||||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
||||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
|
google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 h1:Wgl1rcDNThT+Zn47YyCXOXyX/COgMTIdhJ717F0l4xk=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
|
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||||
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
|
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@@ -815,8 +817,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
|||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
|||||||
@@ -519,9 +519,13 @@ func (m *Manager) executeServiceUpdate(ctx context.Context, transaction store.St
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateProtocolChange(existingService.Mode, service.Mode); err != nil {
|
if existingService.Terminated {
|
||||||
return err
|
return status.Errorf(status.PermissionDenied, "service is terminated and cannot be updated")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validateProtocolChange(existingService.Mode, service.Mode); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
updateInfo.oldCluster = existingService.ProxyCluster
|
updateInfo.oldCluster = existingService.ProxyCluster
|
||||||
updateInfo.domainChanged = existingService.Domain != service.Domain
|
updateInfo.domainChanged = existingService.Domain != service.Domain
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ type Service struct {
|
|||||||
ProxyCluster string `gorm:"index"`
|
ProxyCluster string `gorm:"index"`
|
||||||
Targets []*Target `gorm:"foreignKey:ServiceID;constraint:OnDelete:CASCADE"`
|
Targets []*Target `gorm:"foreignKey:ServiceID;constraint:OnDelete:CASCADE"`
|
||||||
Enabled bool
|
Enabled bool
|
||||||
|
Terminated bool
|
||||||
PassHostHeader bool
|
PassHostHeader bool
|
||||||
RewriteRedirects bool
|
RewriteRedirects bool
|
||||||
Auth AuthConfig `gorm:"serializer:json"`
|
Auth AuthConfig `gorm:"serializer:json"`
|
||||||
@@ -256,7 +257,7 @@ func (s *Service) ToAPIResponse() *api.Service {
|
|||||||
Protocol: api.ServiceTargetProtocol(target.Protocol),
|
Protocol: api.ServiceTargetProtocol(target.Protocol),
|
||||||
TargetId: target.TargetId,
|
TargetId: target.TargetId,
|
||||||
TargetType: api.ServiceTargetTargetType(target.TargetType),
|
TargetType: api.ServiceTargetTargetType(target.TargetType),
|
||||||
Enabled: target.Enabled,
|
Enabled: target.Enabled && !s.Terminated,
|
||||||
}
|
}
|
||||||
opts := targetOptionsToAPI(target.Options)
|
opts := targetOptionsToAPI(target.Options)
|
||||||
if opts == nil {
|
if opts == nil {
|
||||||
@@ -286,7 +287,8 @@ func (s *Service) ToAPIResponse() *api.Service {
|
|||||||
Name: s.Name,
|
Name: s.Name,
|
||||||
Domain: s.Domain,
|
Domain: s.Domain,
|
||||||
Targets: apiTargets,
|
Targets: apiTargets,
|
||||||
Enabled: s.Enabled,
|
Enabled: s.Enabled && !s.Terminated,
|
||||||
|
Terminated: &s.Terminated,
|
||||||
PassHostHeader: &s.PassHostHeader,
|
PassHostHeader: &s.PassHostHeader,
|
||||||
RewriteRedirects: &s.RewriteRedirects,
|
RewriteRedirects: &s.RewriteRedirects,
|
||||||
Auth: authConfig,
|
Auth: authConfig,
|
||||||
@@ -1125,6 +1127,7 @@ func (s *Service) Copy() *Service {
|
|||||||
ProxyCluster: s.ProxyCluster,
|
ProxyCluster: s.ProxyCluster,
|
||||||
Targets: targets,
|
Targets: targets,
|
||||||
Enabled: s.Enabled,
|
Enabled: s.Enabled,
|
||||||
|
Terminated: s.Terminated,
|
||||||
PassHostHeader: s.PassHostHeader,
|
PassHostHeader: s.PassHostHeader,
|
||||||
RewriteRedirects: s.RewriteRedirects,
|
RewriteRedirects: s.RewriteRedirects,
|
||||||
Auth: authCopy,
|
Auth: authCopy,
|
||||||
|
|||||||
@@ -0,0 +1,238 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools/channel"
|
||||||
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Accounts_GetAll(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, true},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - Get all accounts", func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/accounts.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, "/api/accounts", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, http.StatusOK, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := []api.Account{}
|
||||||
|
if err := json.Unmarshal(content, &got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 1, len(got))
|
||||||
|
account := got[0]
|
||||||
|
assert.Equal(t, "test.com", account.Domain)
|
||||||
|
assert.Equal(t, "private", account.DomainCategory)
|
||||||
|
assert.Equal(t, true, account.Settings.PeerLoginExpirationEnabled)
|
||||||
|
assert.Equal(t, 86400, account.Settings.PeerLoginExpiration)
|
||||||
|
assert.Equal(t, false, account.Settings.RegularUsersViewBlocked)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Accounts_Update(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
trueVal := true
|
||||||
|
falseVal := false
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
expectedStatus int
|
||||||
|
requestBody *api.AccountRequest
|
||||||
|
verifyResponse func(t *testing.T, account *api.Account)
|
||||||
|
verifyDB func(t *testing.T, account *types.Account)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Disable peer login expiration",
|
||||||
|
requestBody: &api.AccountRequest{
|
||||||
|
Settings: api.AccountSettings{
|
||||||
|
PeerLoginExpirationEnabled: false,
|
||||||
|
PeerLoginExpiration: 86400,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, account *api.Account) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, false, account.Settings.PeerLoginExpirationEnabled)
|
||||||
|
},
|
||||||
|
verifyDB: func(t *testing.T, dbAccount *types.Account) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, false, dbAccount.Settings.PeerLoginExpirationEnabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update peer login expiration to 48h",
|
||||||
|
requestBody: &api.AccountRequest{
|
||||||
|
Settings: api.AccountSettings{
|
||||||
|
PeerLoginExpirationEnabled: true,
|
||||||
|
PeerLoginExpiration: 172800,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, account *api.Account) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, 172800, account.Settings.PeerLoginExpiration)
|
||||||
|
},
|
||||||
|
verifyDB: func(t *testing.T, dbAccount *types.Account) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, 172800*time.Second, dbAccount.Settings.PeerLoginExpiration)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Enable regular users view blocked",
|
||||||
|
requestBody: &api.AccountRequest{
|
||||||
|
Settings: api.AccountSettings{
|
||||||
|
PeerLoginExpirationEnabled: true,
|
||||||
|
PeerLoginExpiration: 86400,
|
||||||
|
RegularUsersViewBlocked: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, account *api.Account) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, true, account.Settings.RegularUsersViewBlocked)
|
||||||
|
},
|
||||||
|
verifyDB: func(t *testing.T, dbAccount *types.Account) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, true, dbAccount.Settings.RegularUsersViewBlocked)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Enable groups propagation",
|
||||||
|
requestBody: &api.AccountRequest{
|
||||||
|
Settings: api.AccountSettings{
|
||||||
|
PeerLoginExpirationEnabled: true,
|
||||||
|
PeerLoginExpiration: 86400,
|
||||||
|
GroupsPropagationEnabled: &trueVal,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, account *api.Account) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotNil(t, account.Settings.GroupsPropagationEnabled)
|
||||||
|
assert.Equal(t, true, *account.Settings.GroupsPropagationEnabled)
|
||||||
|
},
|
||||||
|
verifyDB: func(t *testing.T, dbAccount *types.Account) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, true, dbAccount.Settings.GroupsPropagationEnabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Enable JWT groups",
|
||||||
|
requestBody: &api.AccountRequest{
|
||||||
|
Settings: api.AccountSettings{
|
||||||
|
PeerLoginExpirationEnabled: true,
|
||||||
|
PeerLoginExpiration: 86400,
|
||||||
|
GroupsPropagationEnabled: &falseVal,
|
||||||
|
JwtGroupsEnabled: &trueVal,
|
||||||
|
JwtGroupsClaimName: stringPointer("groups"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, account *api.Account) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotNil(t, account.Settings.JwtGroupsEnabled)
|
||||||
|
assert.Equal(t, true, *account.Settings.JwtGroupsEnabled)
|
||||||
|
assert.NotNil(t, account.Settings.JwtGroupsClaimName)
|
||||||
|
assert.Equal(t, "groups", *account.Settings.JwtGroupsClaimName)
|
||||||
|
},
|
||||||
|
verifyDB: func(t *testing.T, dbAccount *types.Account) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, true, dbAccount.Settings.JWTGroupsEnabled)
|
||||||
|
assert.Equal(t, "groups", dbAccount.Settings.JWTGroupsClaimName)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/accounts.sql", nil, false)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPut, strings.Replace("/api/accounts/{accountId}", "{accountId}", testing_tools.TestAccountId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := &api.Account{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, testing_tools.TestAccountId, got.Id)
|
||||||
|
assert.Equal(t, "test.com", got.Domain)
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbAccount := testing_tools.VerifyAccountSettings(t, db)
|
||||||
|
tc.verifyDB(t, dbAccount)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringPointer(s string) *string {
|
||||||
|
return &s
|
||||||
|
}
|
||||||
@@ -0,0 +1,554 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools/channel"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Nameservers_GetAll(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - Get all nameservers", func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/dns.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, "/api/dns/nameservers", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, http.StatusOK, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := []api.NameserverGroup{}
|
||||||
|
if err := json.Unmarshal(content, &got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 1, len(got))
|
||||||
|
assert.Equal(t, "testNSGroup", got[0].Name)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Nameservers_GetById(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
nsGroupId string
|
||||||
|
expectedStatus int
|
||||||
|
expectGroup bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get existing nameserver group",
|
||||||
|
nsGroupId: "testNSGroupId",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
expectGroup: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get non-existing nameserver group",
|
||||||
|
nsGroupId: "nonExistingNSGroupId",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
expectGroup: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/dns.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, strings.Replace("/api/dns/nameservers/{nsgroupId}", "{nsgroupId}", tc.nsGroupId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expectGroup {
|
||||||
|
got := &api.NameserverGroup{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, "testNSGroupId", got.Id)
|
||||||
|
assert.Equal(t, "testNSGroup", got.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Nameservers_Create(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
requestBody *api.PostApiDnsNameserversJSONRequestBody
|
||||||
|
expectedStatus int
|
||||||
|
verifyResponse func(t *testing.T, nsGroup *api.NameserverGroup)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Create nameserver group with single NS",
|
||||||
|
requestBody: &api.PostApiDnsNameserversJSONRequestBody{
|
||||||
|
Name: "newNSGroup",
|
||||||
|
Description: "a new nameserver group",
|
||||||
|
Nameservers: []api.Nameserver{
|
||||||
|
{Ip: "8.8.8.8", NsType: "udp", Port: 53},
|
||||||
|
},
|
||||||
|
Groups: []string{testing_tools.TestGroupId},
|
||||||
|
Primary: false,
|
||||||
|
Domains: []string{"test.com"},
|
||||||
|
Enabled: true,
|
||||||
|
SearchDomainsEnabled: false,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, nsGroup *api.NameserverGroup) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotEmpty(t, nsGroup.Id)
|
||||||
|
assert.Equal(t, "newNSGroup", nsGroup.Name)
|
||||||
|
assert.Equal(t, 1, len(nsGroup.Nameservers))
|
||||||
|
assert.Equal(t, false, nsGroup.Primary)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create primary nameserver group",
|
||||||
|
requestBody: &api.PostApiDnsNameserversJSONRequestBody{
|
||||||
|
Name: "primaryNS",
|
||||||
|
Description: "primary nameserver",
|
||||||
|
Nameservers: []api.Nameserver{
|
||||||
|
{Ip: "1.1.1.1", NsType: "udp", Port: 53},
|
||||||
|
},
|
||||||
|
Groups: []string{testing_tools.TestGroupId},
|
||||||
|
Primary: true,
|
||||||
|
Domains: []string{},
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, nsGroup *api.NameserverGroup) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, true, nsGroup.Primary)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create nameserver group with empty groups",
|
||||||
|
requestBody: &api.PostApiDnsNameserversJSONRequestBody{
|
||||||
|
Name: "emptyGroupsNS",
|
||||||
|
Description: "no groups",
|
||||||
|
Nameservers: []api.Nameserver{
|
||||||
|
{Ip: "8.8.8.8", NsType: "udp", Port: 53},
|
||||||
|
},
|
||||||
|
Groups: []string{},
|
||||||
|
Primary: true,
|
||||||
|
Domains: []string{},
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/dns.sql", nil, false)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPost, "/api/dns/nameservers", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.NameserverGroup{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify the created NS group directly in the DB
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbNS := testing_tools.VerifyNSGroupInDB(t, db, got.Id)
|
||||||
|
assert.Equal(t, got.Name, dbNS.Name)
|
||||||
|
assert.Equal(t, got.Primary, dbNS.Primary)
|
||||||
|
assert.Equal(t, len(got.Nameservers), len(dbNS.NameServers))
|
||||||
|
assert.Equal(t, got.Enabled, dbNS.Enabled)
|
||||||
|
assert.Equal(t, got.SearchDomainsEnabled, dbNS.SearchDomainsEnabled)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Nameservers_Update(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
nsGroupId string
|
||||||
|
requestBody *api.PutApiDnsNameserversNsgroupIdJSONRequestBody
|
||||||
|
expectedStatus int
|
||||||
|
verifyResponse func(t *testing.T, nsGroup *api.NameserverGroup)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Update nameserver group name",
|
||||||
|
nsGroupId: "testNSGroupId",
|
||||||
|
requestBody: &api.PutApiDnsNameserversNsgroupIdJSONRequestBody{
|
||||||
|
Name: "updatedNSGroup",
|
||||||
|
Description: "updated description",
|
||||||
|
Nameservers: []api.Nameserver{
|
||||||
|
{Ip: "1.1.1.1", NsType: "udp", Port: 53},
|
||||||
|
},
|
||||||
|
Groups: []string{testing_tools.TestGroupId},
|
||||||
|
Primary: false,
|
||||||
|
Domains: []string{"example.com"},
|
||||||
|
Enabled: true,
|
||||||
|
SearchDomainsEnabled: false,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, nsGroup *api.NameserverGroup) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, "updatedNSGroup", nsGroup.Name)
|
||||||
|
assert.Equal(t, "updated description", nsGroup.Description)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update non-existing nameserver group",
|
||||||
|
nsGroupId: "nonExistingNSGroupId",
|
||||||
|
requestBody: &api.PutApiDnsNameserversNsgroupIdJSONRequestBody{
|
||||||
|
Name: "whatever",
|
||||||
|
Nameservers: []api.Nameserver{
|
||||||
|
{Ip: "1.1.1.1", NsType: "udp", Port: 53},
|
||||||
|
},
|
||||||
|
Groups: []string{testing_tools.TestGroupId},
|
||||||
|
Primary: true,
|
||||||
|
Domains: []string{},
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/dns.sql", nil, false)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPut, strings.Replace("/api/dns/nameservers/{nsgroupId}", "{nsgroupId}", tc.nsGroupId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.NameserverGroup{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify the updated NS group directly in the DB
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbNS := testing_tools.VerifyNSGroupInDB(t, db, tc.nsGroupId)
|
||||||
|
assert.Equal(t, "updatedNSGroup", dbNS.Name)
|
||||||
|
assert.Equal(t, "updated description", dbNS.Description)
|
||||||
|
assert.Equal(t, false, dbNS.Primary)
|
||||||
|
assert.Equal(t, true, dbNS.Enabled)
|
||||||
|
assert.Equal(t, 1, len(dbNS.NameServers))
|
||||||
|
assert.Equal(t, false, dbNS.SearchDomainsEnabled)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Nameservers_Delete(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
nsGroupId string
|
||||||
|
expectedStatus int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Delete existing nameserver group",
|
||||||
|
nsGroupId: "testNSGroupId",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Delete non-existing nameserver group",
|
||||||
|
nsGroupId: "nonExistingNSGroupId",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/dns.sql", nil, false)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodDelete, strings.Replace("/api/dns/nameservers/{nsgroupId}", "{nsgroupId}", tc.nsGroupId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
|
||||||
|
// Verify deletion in DB for successful deletes by privileged users
|
||||||
|
if tc.expectedStatus == http.StatusOK && user.expectResponse {
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
testing_tools.VerifyNSGroupNotInDB(t, db, tc.nsGroupId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_DnsSettings_Get(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - Get DNS settings", func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/dns.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, "/api/dns/settings", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, http.StatusOK, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := &api.DNSSettings{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NotNil(t, got.DisabledManagementGroups)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_DnsSettings_Update(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
requestBody *api.PutApiDnsSettingsJSONRequestBody
|
||||||
|
expectedStatus int
|
||||||
|
verifyResponse func(t *testing.T, settings *api.DNSSettings)
|
||||||
|
expectedDBDisabledMgmtLen int
|
||||||
|
expectedDBDisabledMgmtItem string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Update disabled management groups",
|
||||||
|
requestBody: &api.PutApiDnsSettingsJSONRequestBody{
|
||||||
|
DisabledManagementGroups: []string{testing_tools.TestGroupId},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, settings *api.DNSSettings) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, 1, len(settings.DisabledManagementGroups))
|
||||||
|
assert.Equal(t, testing_tools.TestGroupId, settings.DisabledManagementGroups[0])
|
||||||
|
},
|
||||||
|
expectedDBDisabledMgmtLen: 1,
|
||||||
|
expectedDBDisabledMgmtItem: testing_tools.TestGroupId,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update with empty disabled management groups",
|
||||||
|
requestBody: &api.PutApiDnsSettingsJSONRequestBody{
|
||||||
|
DisabledManagementGroups: []string{},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, settings *api.DNSSettings) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, 0, len(settings.DisabledManagementGroups))
|
||||||
|
},
|
||||||
|
expectedDBDisabledMgmtLen: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update with non-existing group",
|
||||||
|
requestBody: &api.PutApiDnsSettingsJSONRequestBody{
|
||||||
|
DisabledManagementGroups: []string{"nonExistingGroupId"},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/dns.sql", nil, false)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPut, "/api/dns/settings", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.DNSSettings{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify DNS settings directly in the DB
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbAccount := testing_tools.VerifyAccountSettings(t, db)
|
||||||
|
assert.Equal(t, tc.expectedDBDisabledMgmtLen, len(dbAccount.DNSSettings.DisabledManagementGroups))
|
||||||
|
if tc.expectedDBDisabledMgmtItem != "" {
|
||||||
|
assert.Contains(t, dbAccount.DNSSettings.DisabledManagementGroups, tc.expectedDBDisabledMgmtItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools/channel"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Events_GetAll(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - Get all events", func(t *testing.T) {
|
||||||
|
apiHandler, _, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/events.sql", nil, false)
|
||||||
|
|
||||||
|
// First, perform a mutation to generate an event (create a group as admin)
|
||||||
|
groupBody, err := json.Marshal(&api.GroupRequest{Name: "eventTestGroup"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal group request: %v", err)
|
||||||
|
}
|
||||||
|
createReq := testing_tools.BuildRequest(t, groupBody, http.MethodPost, "/api/groups", testing_tools.TestAdminId)
|
||||||
|
createRecorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(createRecorder, createReq)
|
||||||
|
assert.Equal(t, http.StatusOK, createRecorder.Code, "Failed to create group to generate event")
|
||||||
|
|
||||||
|
// Now query events
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, "/api/events", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, http.StatusOK, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := []api.Event{}
|
||||||
|
if err := json.Unmarshal(content, &got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.GreaterOrEqual(t, len(got), 1, "Expected at least one event after creating a group")
|
||||||
|
|
||||||
|
// Verify the group creation event exists
|
||||||
|
found := false
|
||||||
|
for _, event := range got {
|
||||||
|
if event.ActivityCode == "group.add" {
|
||||||
|
found = true
|
||||||
|
assert.Equal(t, testing_tools.TestAdminId, event.InitiatorId)
|
||||||
|
assert.Equal(t, "Group created", event.Activity)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.True(t, found, "Expected to find a group.add event")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Events_GetAll_Empty(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/events.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, "/api/events", testing_tools.TestAdminId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, http.StatusOK, true)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := []api.Event{}
|
||||||
|
if err := json.Unmarshal(content, &got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 0, len(got), "Expected empty events list when no mutations have been performed")
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,382 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools/channel"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Groups_GetAll(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, true},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - Get all groups", func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/groups.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, "/api/groups", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, http.StatusOK, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := []api.Group{}
|
||||||
|
if err := json.Unmarshal(content, &got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.GreaterOrEqual(t, len(got), 2)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Groups_GetById(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, true},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
groupId string
|
||||||
|
expectedStatus int
|
||||||
|
expectGroup bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get existing group",
|
||||||
|
groupId: testing_tools.TestGroupId,
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
expectGroup: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get non-existing group",
|
||||||
|
groupId: "nonExistingGroupId",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
expectGroup: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/groups.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, strings.Replace("/api/groups/{groupId}", "{groupId}", tc.groupId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expectGroup {
|
||||||
|
got := &api.Group{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, tc.groupId, got.Id)
|
||||||
|
assert.Equal(t, "testGroupName", got.Name)
|
||||||
|
assert.Equal(t, 1, got.PeersCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Groups_Create(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
requestBody *api.GroupRequest
|
||||||
|
expectedStatus int
|
||||||
|
verifyResponse func(t *testing.T, group *api.Group)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Create group with valid name",
|
||||||
|
requestBody: &api.GroupRequest{
|
||||||
|
Name: "brandNewGroup",
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, group *api.Group) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotEmpty(t, group.Id)
|
||||||
|
assert.Equal(t, "brandNewGroup", group.Name)
|
||||||
|
assert.Equal(t, 0, group.PeersCount)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create group with peers",
|
||||||
|
requestBody: &api.GroupRequest{
|
||||||
|
Name: "groupWithPeers",
|
||||||
|
Peers: &[]string{testing_tools.TestPeerId},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, group *api.Group) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotEmpty(t, group.Id)
|
||||||
|
assert.Equal(t, "groupWithPeers", group.Name)
|
||||||
|
assert.Equal(t, 1, group.PeersCount)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create group with empty name",
|
||||||
|
requestBody: &api.GroupRequest{
|
||||||
|
Name: "",
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/groups.sql", nil, false)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPost, "/api/groups", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.Group{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify group exists in DB
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbGroup := testing_tools.VerifyGroupInDB(t, db, got.Id)
|
||||||
|
assert.Equal(t, tc.requestBody.Name, dbGroup.Name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Groups_Update(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
groupId string
|
||||||
|
requestBody *api.GroupRequest
|
||||||
|
expectedStatus int
|
||||||
|
verifyResponse func(t *testing.T, group *api.Group)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Update group name",
|
||||||
|
groupId: testing_tools.TestGroupId,
|
||||||
|
requestBody: &api.GroupRequest{
|
||||||
|
Name: "updatedGroupName",
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, group *api.Group) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, testing_tools.TestGroupId, group.Id)
|
||||||
|
assert.Equal(t, "updatedGroupName", group.Name)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update group peers",
|
||||||
|
groupId: testing_tools.TestGroupId,
|
||||||
|
requestBody: &api.GroupRequest{
|
||||||
|
Name: "testGroupName",
|
||||||
|
Peers: &[]string{},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, group *api.Group) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, 0, group.PeersCount)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update with empty name",
|
||||||
|
groupId: testing_tools.TestGroupId,
|
||||||
|
requestBody: &api.GroupRequest{
|
||||||
|
Name: "",
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update non-existing group",
|
||||||
|
groupId: "nonExistingGroupId",
|
||||||
|
requestBody: &api.GroupRequest{
|
||||||
|
Name: "someName",
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/groups.sql", nil, false)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPut, strings.Replace("/api/groups/{groupId}", "{groupId}", tc.groupId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.Group{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify updated group in DB
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbGroup := testing_tools.VerifyGroupInDB(t, db, tc.groupId)
|
||||||
|
assert.Equal(t, tc.requestBody.Name, dbGroup.Name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Groups_Delete(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
groupId string
|
||||||
|
expectedStatus int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Delete existing group not in use",
|
||||||
|
groupId: testing_tools.NewGroupId,
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Delete non-existing group",
|
||||||
|
groupId: "nonExistingGroupId",
|
||||||
|
expectedStatus: http.StatusBadRequest,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/groups.sql", nil, false)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodDelete, strings.Replace("/api/groups/{groupId}", "{groupId}", tc.groupId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
_, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if expectResponse && tc.expectedStatus == http.StatusOK {
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
testing_tools.VerifyGroupNotInDB(t, db, tc.groupId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,605 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools/channel"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
testPeerId2 = "testPeerId2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Peers_GetAll(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Regular user",
|
||||||
|
userId: testing_tools.TestUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin user",
|
||||||
|
userId: testing_tools.TestAdminId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Owner user",
|
||||||
|
userId: testing_tools.TestOwnerId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Regular service user",
|
||||||
|
userId: testing_tools.TestServiceUserId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin service user",
|
||||||
|
userId: testing_tools.TestServiceAdminId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Blocked user",
|
||||||
|
userId: testing_tools.BlockedUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Other user",
|
||||||
|
userId: testing_tools.OtherUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid token",
|
||||||
|
userId: testing_tools.InvalidToken,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - Get all peers", func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/peers_integration.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, "/api/peers", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, http.StatusOK, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var got []api.PeerBatch
|
||||||
|
if err := json.Unmarshal(content, &got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.GreaterOrEqual(t, len(got), 2, "Expected at least 2 peers")
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Peers_GetById(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Regular user",
|
||||||
|
userId: testing_tools.TestUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin user",
|
||||||
|
userId: testing_tools.TestAdminId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Owner user",
|
||||||
|
userId: testing_tools.TestOwnerId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Regular service user",
|
||||||
|
userId: testing_tools.TestServiceUserId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin service user",
|
||||||
|
userId: testing_tools.TestServiceAdminId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Blocked user",
|
||||||
|
userId: testing_tools.BlockedUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Other user",
|
||||||
|
userId: testing_tools.OtherUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid token",
|
||||||
|
userId: testing_tools.InvalidToken,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
expectedStatus int
|
||||||
|
requestType string
|
||||||
|
requestPath string
|
||||||
|
requestId string
|
||||||
|
verifyResponse func(t *testing.T, peer *api.Peer)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get existing peer",
|
||||||
|
requestType: http.MethodGet,
|
||||||
|
requestPath: "/api/peers/{peerId}",
|
||||||
|
requestId: testing_tools.TestPeerId,
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, peer *api.Peer) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, testing_tools.TestPeerId, peer.Id)
|
||||||
|
assert.Equal(t, "test-peer-1", peer.Name)
|
||||||
|
assert.Equal(t, "test-host-1", peer.Hostname)
|
||||||
|
assert.Equal(t, "Debian GNU/Linux ", peer.Os)
|
||||||
|
assert.Equal(t, "0.12.0", peer.Version)
|
||||||
|
assert.Equal(t, false, peer.SshEnabled)
|
||||||
|
assert.Equal(t, true, peer.LoginExpirationEnabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get second existing peer",
|
||||||
|
requestType: http.MethodGet,
|
||||||
|
requestPath: "/api/peers/{peerId}",
|
||||||
|
requestId: testPeerId2,
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, peer *api.Peer) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, testPeerId2, peer.Id)
|
||||||
|
assert.Equal(t, "test-peer-2", peer.Name)
|
||||||
|
assert.Equal(t, "test-host-2", peer.Hostname)
|
||||||
|
assert.Equal(t, "Ubuntu ", peer.Os)
|
||||||
|
assert.Equal(t, true, peer.SshEnabled)
|
||||||
|
assert.Equal(t, false, peer.LoginExpirationEnabled)
|
||||||
|
assert.Equal(t, true, peer.Connected)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get non-existing peer",
|
||||||
|
requestType: http.MethodGet,
|
||||||
|
requestPath: "/api/peers/{peerId}",
|
||||||
|
requestId: "nonExistingPeerId",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
verifyResponse: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/peers_integration.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, tc.requestType, strings.Replace(tc.requestPath, "{peerId}", tc.requestId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.Peer{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Peers_Update(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Regular user",
|
||||||
|
userId: testing_tools.TestUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin user",
|
||||||
|
userId: testing_tools.TestAdminId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Owner user",
|
||||||
|
userId: testing_tools.TestOwnerId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Regular service user",
|
||||||
|
userId: testing_tools.TestServiceUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin service user",
|
||||||
|
userId: testing_tools.TestServiceAdminId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Blocked user",
|
||||||
|
userId: testing_tools.BlockedUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Other user",
|
||||||
|
userId: testing_tools.OtherUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid token",
|
||||||
|
userId: testing_tools.InvalidToken,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
expectedStatus int
|
||||||
|
requestBody *api.PeerRequest
|
||||||
|
requestType string
|
||||||
|
requestPath string
|
||||||
|
requestId string
|
||||||
|
verifyResponse func(t *testing.T, peer *api.Peer)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Update peer name",
|
||||||
|
requestType: http.MethodPut,
|
||||||
|
requestPath: "/api/peers/{peerId}",
|
||||||
|
requestId: testing_tools.TestPeerId,
|
||||||
|
requestBody: &api.PeerRequest{
|
||||||
|
Name: "updated-peer-name",
|
||||||
|
SshEnabled: false,
|
||||||
|
LoginExpirationEnabled: true,
|
||||||
|
InactivityExpirationEnabled: false,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, peer *api.Peer) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, testing_tools.TestPeerId, peer.Id)
|
||||||
|
assert.Equal(t, "updated-peer-name", peer.Name)
|
||||||
|
assert.Equal(t, false, peer.SshEnabled)
|
||||||
|
assert.Equal(t, true, peer.LoginExpirationEnabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Enable SSH on peer",
|
||||||
|
requestType: http.MethodPut,
|
||||||
|
requestPath: "/api/peers/{peerId}",
|
||||||
|
requestId: testing_tools.TestPeerId,
|
||||||
|
requestBody: &api.PeerRequest{
|
||||||
|
Name: "test-peer-1",
|
||||||
|
SshEnabled: true,
|
||||||
|
LoginExpirationEnabled: true,
|
||||||
|
InactivityExpirationEnabled: false,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, peer *api.Peer) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, testing_tools.TestPeerId, peer.Id)
|
||||||
|
assert.Equal(t, "test-peer-1", peer.Name)
|
||||||
|
assert.Equal(t, true, peer.SshEnabled)
|
||||||
|
assert.Equal(t, true, peer.LoginExpirationEnabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Disable login expiration on peer",
|
||||||
|
requestType: http.MethodPut,
|
||||||
|
requestPath: "/api/peers/{peerId}",
|
||||||
|
requestId: testing_tools.TestPeerId,
|
||||||
|
requestBody: &api.PeerRequest{
|
||||||
|
Name: "test-peer-1",
|
||||||
|
SshEnabled: false,
|
||||||
|
LoginExpirationEnabled: false,
|
||||||
|
InactivityExpirationEnabled: false,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, peer *api.Peer) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, testing_tools.TestPeerId, peer.Id)
|
||||||
|
assert.Equal(t, false, peer.LoginExpirationEnabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update non-existing peer",
|
||||||
|
requestType: http.MethodPut,
|
||||||
|
requestPath: "/api/peers/{peerId}",
|
||||||
|
requestId: "nonExistingPeerId",
|
||||||
|
requestBody: &api.PeerRequest{
|
||||||
|
Name: "updated-name",
|
||||||
|
SshEnabled: false,
|
||||||
|
LoginExpirationEnabled: false,
|
||||||
|
InactivityExpirationEnabled: false,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
verifyResponse: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/peers_integration.sql", nil, false)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, tc.requestType, strings.Replace(tc.requestPath, "{peerId}", tc.requestId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.Peer{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify updated peer in DB
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbPeer := testing_tools.VerifyPeerInDB(t, db, tc.requestId)
|
||||||
|
assert.Equal(t, tc.requestBody.Name, dbPeer.Name)
|
||||||
|
assert.Equal(t, tc.requestBody.SshEnabled, dbPeer.SSHEnabled)
|
||||||
|
assert.Equal(t, tc.requestBody.LoginExpirationEnabled, dbPeer.LoginExpirationEnabled)
|
||||||
|
assert.Equal(t, tc.requestBody.InactivityExpirationEnabled, dbPeer.InactivityExpirationEnabled)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Peers_Delete(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Regular user",
|
||||||
|
userId: testing_tools.TestUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin user",
|
||||||
|
userId: testing_tools.TestAdminId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Owner user",
|
||||||
|
userId: testing_tools.TestOwnerId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Regular service user",
|
||||||
|
userId: testing_tools.TestServiceUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin service user",
|
||||||
|
userId: testing_tools.TestServiceAdminId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Blocked user",
|
||||||
|
userId: testing_tools.BlockedUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Other user",
|
||||||
|
userId: testing_tools.OtherUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid token",
|
||||||
|
userId: testing_tools.InvalidToken,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
expectedStatus int
|
||||||
|
requestType string
|
||||||
|
requestPath string
|
||||||
|
requestId string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Delete existing peer",
|
||||||
|
requestType: http.MethodDelete,
|
||||||
|
requestPath: "/api/peers/{peerId}",
|
||||||
|
requestId: testPeerId2,
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Delete non-existing peer",
|
||||||
|
requestType: http.MethodDelete,
|
||||||
|
requestPath: "/api/peers/{peerId}",
|
||||||
|
requestId: "nonExistingPeerId",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/peers_integration.sql", nil, false)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, tc.requestType, strings.Replace(tc.requestPath, "{peerId}", tc.requestId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
_, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify peer is actually deleted in DB
|
||||||
|
if tc.expectedStatus == http.StatusOK {
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
testing_tools.VerifyPeerNotInDB(t, db, tc.requestId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Peers_GetAccessiblePeers(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Regular user",
|
||||||
|
userId: testing_tools.TestUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin user",
|
||||||
|
userId: testing_tools.TestAdminId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Owner user",
|
||||||
|
userId: testing_tools.TestOwnerId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Regular service user",
|
||||||
|
userId: testing_tools.TestServiceUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin service user",
|
||||||
|
userId: testing_tools.TestServiceAdminId,
|
||||||
|
expectResponse: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Blocked user",
|
||||||
|
userId: testing_tools.BlockedUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Other user",
|
||||||
|
userId: testing_tools.OtherUserId,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid token",
|
||||||
|
userId: testing_tools.InvalidToken,
|
||||||
|
expectResponse: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
expectedStatus int
|
||||||
|
requestType string
|
||||||
|
requestPath string
|
||||||
|
requestId string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get accessible peers for existing peer",
|
||||||
|
requestType: http.MethodGet,
|
||||||
|
requestPath: "/api/peers/{peerId}/accessible-peers",
|
||||||
|
requestId: testing_tools.TestPeerId,
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get accessible peers for non-existing peer",
|
||||||
|
requestType: http.MethodGet,
|
||||||
|
requestPath: "/api/peers/{peerId}/accessible-peers",
|
||||||
|
requestId: "nonExistingPeerId",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/peers_integration.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, tc.requestType, strings.Replace(tc.requestPath, "{peerId}", tc.requestId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expectedStatus == http.StatusOK {
|
||||||
|
var got []api.AccessiblePeer
|
||||||
|
if err := json.Unmarshal(content, &got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
// The accessible peers list should be a valid array (may be empty if no policies connect peers)
|
||||||
|
assert.NotNil(t, got, "Expected accessible peers to be a valid array")
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,488 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools/channel"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Policies_GetAll(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - Get all policies", func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/policies.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, "/api/policies", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, http.StatusOK, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := []api.Policy{}
|
||||||
|
if err := json.Unmarshal(content, &got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 1, len(got))
|
||||||
|
assert.Equal(t, "testPolicy", got[0].Name)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Policies_GetById(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
policyId string
|
||||||
|
expectedStatus int
|
||||||
|
expectPolicy bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get existing policy",
|
||||||
|
policyId: "testPolicyId",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
expectPolicy: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get non-existing policy",
|
||||||
|
policyId: "nonExistingPolicyId",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
expectPolicy: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/policies.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, strings.Replace("/api/policies/{policyId}", "{policyId}", tc.policyId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expectPolicy {
|
||||||
|
got := &api.Policy{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
assert.NotNil(t, got.Id)
|
||||||
|
assert.Equal(t, tc.policyId, *got.Id)
|
||||||
|
assert.Equal(t, "testPolicy", got.Name)
|
||||||
|
assert.Equal(t, true, got.Enabled)
|
||||||
|
assert.GreaterOrEqual(t, len(got.Rules), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Policies_Create(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
srcGroups := []string{testing_tools.TestGroupId}
|
||||||
|
dstGroups := []string{testing_tools.TestGroupId}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
requestBody *api.PolicyCreate
|
||||||
|
expectedStatus int
|
||||||
|
verifyResponse func(t *testing.T, policy *api.Policy)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Create policy with accept rule",
|
||||||
|
requestBody: &api.PolicyCreate{
|
||||||
|
Name: "newPolicy",
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []api.PolicyRuleUpdate{
|
||||||
|
{
|
||||||
|
Name: "allowAll",
|
||||||
|
Enabled: true,
|
||||||
|
Action: "accept",
|
||||||
|
Protocol: "all",
|
||||||
|
Bidirectional: true,
|
||||||
|
Sources: &srcGroups,
|
||||||
|
Destinations: &dstGroups,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, policy *api.Policy) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotNil(t, policy.Id)
|
||||||
|
assert.Equal(t, "newPolicy", policy.Name)
|
||||||
|
assert.Equal(t, true, policy.Enabled)
|
||||||
|
assert.Equal(t, 1, len(policy.Rules))
|
||||||
|
assert.Equal(t, "allowAll", policy.Rules[0].Name)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create policy with drop rule",
|
||||||
|
requestBody: &api.PolicyCreate{
|
||||||
|
Name: "dropPolicy",
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []api.PolicyRuleUpdate{
|
||||||
|
{
|
||||||
|
Name: "dropAll",
|
||||||
|
Enabled: true,
|
||||||
|
Action: "drop",
|
||||||
|
Protocol: "all",
|
||||||
|
Bidirectional: true,
|
||||||
|
Sources: &srcGroups,
|
||||||
|
Destinations: &dstGroups,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, policy *api.Policy) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, "dropPolicy", policy.Name)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create policy with TCP rule and ports",
|
||||||
|
requestBody: &api.PolicyCreate{
|
||||||
|
Name: "tcpPolicy",
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []api.PolicyRuleUpdate{
|
||||||
|
{
|
||||||
|
Name: "tcpRule",
|
||||||
|
Enabled: true,
|
||||||
|
Action: "accept",
|
||||||
|
Protocol: "tcp",
|
||||||
|
Bidirectional: true,
|
||||||
|
Sources: &srcGroups,
|
||||||
|
Destinations: &dstGroups,
|
||||||
|
Ports: &[]string{"80", "443"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, policy *api.Policy) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, "tcpPolicy", policy.Name)
|
||||||
|
assert.NotNil(t, policy.Rules[0].Ports)
|
||||||
|
assert.Equal(t, 2, len(*policy.Rules[0].Ports))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create policy with empty name",
|
||||||
|
requestBody: &api.PolicyCreate{
|
||||||
|
Name: "",
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []api.PolicyRuleUpdate{
|
||||||
|
{
|
||||||
|
Name: "rule",
|
||||||
|
Enabled: true,
|
||||||
|
Action: "accept",
|
||||||
|
Protocol: "all",
|
||||||
|
Sources: &srcGroups,
|
||||||
|
Destinations: &dstGroups,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create policy with no rules",
|
||||||
|
requestBody: &api.PolicyCreate{
|
||||||
|
Name: "noRulesPolicy",
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []api.PolicyRuleUpdate{},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/policies.sql", nil, false)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPost, "/api/policies", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.Policy{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify policy exists in DB with correct fields
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbPolicy := testing_tools.VerifyPolicyInDB(t, db, *got.Id)
|
||||||
|
assert.Equal(t, tc.requestBody.Name, dbPolicy.Name)
|
||||||
|
assert.Equal(t, tc.requestBody.Enabled, dbPolicy.Enabled)
|
||||||
|
assert.Equal(t, len(tc.requestBody.Rules), len(dbPolicy.Rules))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Policies_Update(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
srcGroups := []string{testing_tools.TestGroupId}
|
||||||
|
dstGroups := []string{testing_tools.TestGroupId}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
policyId string
|
||||||
|
requestBody *api.PolicyCreate
|
||||||
|
expectedStatus int
|
||||||
|
verifyResponse func(t *testing.T, policy *api.Policy)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Update policy name",
|
||||||
|
policyId: "testPolicyId",
|
||||||
|
requestBody: &api.PolicyCreate{
|
||||||
|
Name: "updatedPolicy",
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []api.PolicyRuleUpdate{
|
||||||
|
{
|
||||||
|
Name: "testRule",
|
||||||
|
Enabled: true,
|
||||||
|
Action: "accept",
|
||||||
|
Protocol: "all",
|
||||||
|
Bidirectional: true,
|
||||||
|
Sources: &srcGroups,
|
||||||
|
Destinations: &dstGroups,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, policy *api.Policy) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, "updatedPolicy", policy.Name)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update policy enabled state",
|
||||||
|
policyId: "testPolicyId",
|
||||||
|
requestBody: &api.PolicyCreate{
|
||||||
|
Name: "testPolicy",
|
||||||
|
Enabled: false,
|
||||||
|
Rules: []api.PolicyRuleUpdate{
|
||||||
|
{
|
||||||
|
Name: "testRule",
|
||||||
|
Enabled: true,
|
||||||
|
Action: "accept",
|
||||||
|
Protocol: "all",
|
||||||
|
Bidirectional: true,
|
||||||
|
Sources: &srcGroups,
|
||||||
|
Destinations: &dstGroups,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, policy *api.Policy) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, false, policy.Enabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update non-existing policy",
|
||||||
|
policyId: "nonExistingPolicyId",
|
||||||
|
requestBody: &api.PolicyCreate{
|
||||||
|
Name: "whatever",
|
||||||
|
Enabled: true,
|
||||||
|
Rules: []api.PolicyRuleUpdate{
|
||||||
|
{
|
||||||
|
Name: "rule",
|
||||||
|
Enabled: true,
|
||||||
|
Action: "accept",
|
||||||
|
Protocol: "all",
|
||||||
|
Sources: &srcGroups,
|
||||||
|
Destinations: &dstGroups,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/policies.sql", nil, false)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPut, strings.Replace("/api/policies/{policyId}", "{policyId}", tc.policyId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.Policy{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify updated policy in DB
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbPolicy := testing_tools.VerifyPolicyInDB(t, db, tc.policyId)
|
||||||
|
assert.Equal(t, tc.requestBody.Name, dbPolicy.Name)
|
||||||
|
assert.Equal(t, tc.requestBody.Enabled, dbPolicy.Enabled)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Policies_Delete(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
policyId string
|
||||||
|
expectedStatus int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Delete existing policy",
|
||||||
|
policyId: "testPolicyId",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Delete non-existing policy",
|
||||||
|
policyId: "nonExistingPolicyId",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/policies.sql", nil, false)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodDelete, strings.Replace("/api/policies/{policyId}", "{policyId}", tc.policyId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
_, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if expectResponse && tc.expectedStatus == http.StatusOK {
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
testing_tools.VerifyPolicyNotInDB(t, db, tc.policyId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,455 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools/channel"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Routes_GetAll(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - Get all routes", func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/routes.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, "/api/routes", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, http.StatusOK, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := []api.Route{}
|
||||||
|
if err := json.Unmarshal(content, &got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 2, len(got))
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Routes_GetById(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
routeId string
|
||||||
|
expectedStatus int
|
||||||
|
expectRoute bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get existing route",
|
||||||
|
routeId: "testRouteId",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
expectRoute: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get non-existing route",
|
||||||
|
routeId: "nonExistingRouteId",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
expectRoute: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/routes.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, strings.Replace("/api/routes/{routeId}", "{routeId}", tc.routeId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expectRoute {
|
||||||
|
got := &api.Route{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, tc.routeId, got.Id)
|
||||||
|
assert.Equal(t, "Test Network Route", got.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Routes_Create(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
networkCIDR := "10.10.0.0/24"
|
||||||
|
peerID := testing_tools.TestPeerId
|
||||||
|
peerGroups := []string{"peerGroupId"}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
requestBody *api.RouteRequest
|
||||||
|
expectedStatus int
|
||||||
|
verifyResponse func(t *testing.T, route *api.Route)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Create network route with peer",
|
||||||
|
requestBody: &api.RouteRequest{
|
||||||
|
Description: "New network route",
|
||||||
|
Network: &networkCIDR,
|
||||||
|
Peer: &peerID,
|
||||||
|
NetworkId: "newNet",
|
||||||
|
Metric: 100,
|
||||||
|
Masquerade: true,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{testing_tools.TestGroupId},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, route *api.Route) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotEmpty(t, route.Id)
|
||||||
|
assert.Equal(t, "New network route", route.Description)
|
||||||
|
assert.Equal(t, 100, route.Metric)
|
||||||
|
assert.Equal(t, true, route.Masquerade)
|
||||||
|
assert.Equal(t, true, route.Enabled)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create network route with peer groups",
|
||||||
|
requestBody: &api.RouteRequest{
|
||||||
|
Description: "Route with peer groups",
|
||||||
|
Network: &networkCIDR,
|
||||||
|
PeerGroups: &peerGroups,
|
||||||
|
NetworkId: "peerGroupNet",
|
||||||
|
Metric: 150,
|
||||||
|
Masquerade: false,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{testing_tools.TestGroupId},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, route *api.Route) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotEmpty(t, route.Id)
|
||||||
|
assert.Equal(t, "Route with peer groups", route.Description)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create route with empty network_id",
|
||||||
|
requestBody: &api.RouteRequest{
|
||||||
|
Description: "Empty net id",
|
||||||
|
Network: &networkCIDR,
|
||||||
|
Peer: &peerID,
|
||||||
|
NetworkId: "",
|
||||||
|
Metric: 100,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{testing_tools.TestGroupId},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create route with metric 0",
|
||||||
|
requestBody: &api.RouteRequest{
|
||||||
|
Description: "Zero metric",
|
||||||
|
Network: &networkCIDR,
|
||||||
|
Peer: &peerID,
|
||||||
|
NetworkId: "zeroMetric",
|
||||||
|
Metric: 0,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{testing_tools.TestGroupId},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create route with metric 10000",
|
||||||
|
requestBody: &api.RouteRequest{
|
||||||
|
Description: "High metric",
|
||||||
|
Network: &networkCIDR,
|
||||||
|
Peer: &peerID,
|
||||||
|
NetworkId: "highMetric",
|
||||||
|
Metric: 10000,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{testing_tools.TestGroupId},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/routes.sql", nil, false)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPost, "/api/routes", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.Route{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify route exists in DB with correct fields
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbRoute := testing_tools.VerifyRouteInDB(t, db, route.ID(got.Id))
|
||||||
|
assert.Equal(t, tc.requestBody.Description, dbRoute.Description)
|
||||||
|
assert.Equal(t, tc.requestBody.Metric, dbRoute.Metric)
|
||||||
|
assert.Equal(t, tc.requestBody.Masquerade, dbRoute.Masquerade)
|
||||||
|
assert.Equal(t, tc.requestBody.Enabled, dbRoute.Enabled)
|
||||||
|
assert.Equal(t, route.NetID(tc.requestBody.NetworkId), dbRoute.NetID)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Routes_Update(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
networkCIDR := "10.0.0.0/24"
|
||||||
|
peerID := testing_tools.TestPeerId
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
routeId string
|
||||||
|
requestBody *api.RouteRequest
|
||||||
|
expectedStatus int
|
||||||
|
verifyResponse func(t *testing.T, route *api.Route)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Update route description",
|
||||||
|
routeId: "testRouteId",
|
||||||
|
requestBody: &api.RouteRequest{
|
||||||
|
Description: "Updated description",
|
||||||
|
Network: &networkCIDR,
|
||||||
|
Peer: &peerID,
|
||||||
|
NetworkId: "testNet",
|
||||||
|
Metric: 100,
|
||||||
|
Masquerade: true,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{testing_tools.TestGroupId},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, route *api.Route) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, "testRouteId", route.Id)
|
||||||
|
assert.Equal(t, "Updated description", route.Description)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update route metric",
|
||||||
|
routeId: "testRouteId",
|
||||||
|
requestBody: &api.RouteRequest{
|
||||||
|
Description: "Test Network Route",
|
||||||
|
Network: &networkCIDR,
|
||||||
|
Peer: &peerID,
|
||||||
|
NetworkId: "testNet",
|
||||||
|
Metric: 500,
|
||||||
|
Masquerade: true,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{testing_tools.TestGroupId},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, route *api.Route) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, 500, route.Metric)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update non-existing route",
|
||||||
|
routeId: "nonExistingRouteId",
|
||||||
|
requestBody: &api.RouteRequest{
|
||||||
|
Description: "whatever",
|
||||||
|
Network: &networkCIDR,
|
||||||
|
Peer: &peerID,
|
||||||
|
NetworkId: "testNet",
|
||||||
|
Metric: 100,
|
||||||
|
Enabled: true,
|
||||||
|
Groups: []string{testing_tools.TestGroupId},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/routes.sql", nil, false)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPut, strings.Replace("/api/routes/{routeId}", "{routeId}", tc.routeId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.Route{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify updated route in DB
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbRoute := testing_tools.VerifyRouteInDB(t, db, route.ID(got.Id))
|
||||||
|
assert.Equal(t, tc.requestBody.Description, dbRoute.Description)
|
||||||
|
assert.Equal(t, tc.requestBody.Metric, dbRoute.Metric)
|
||||||
|
assert.Equal(t, tc.requestBody.Masquerade, dbRoute.Masquerade)
|
||||||
|
assert.Equal(t, tc.requestBody.Enabled, dbRoute.Enabled)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Routes_Delete(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
routeId string
|
||||||
|
expectedStatus int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Delete existing route",
|
||||||
|
routeId: "testRouteId",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Delete non-existing route",
|
||||||
|
routeId: "nonExistingRouteId",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/routes.sql", nil, false)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodDelete, strings.Replace("/api/routes/{routeId}", "{routeId}", tc.routeId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
|
||||||
|
// Verify route was deleted from DB for successful deletes
|
||||||
|
if tc.expectedStatus == http.StatusOK && user.expectResponse {
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
testing_tools.VerifyRouteNotInDB(t, db, route.ID(tc.routeId))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@@ -14,7 +13,6 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/server/http/handlers/setup_keys"
|
|
||||||
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools"
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools"
|
||||||
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools/channel"
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools/channel"
|
||||||
"github.com/netbirdio/netbird/shared/management/http/api"
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
@@ -254,7 +252,7 @@ func Test_SetupKeys_Create(t *testing.T) {
|
|||||||
expectedResponse: nil,
|
expectedResponse: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Create Setup Key",
|
name: "Create Setup Key with nil AutoGroups",
|
||||||
requestType: http.MethodPost,
|
requestType: http.MethodPost,
|
||||||
requestPath: "/api/setup-keys",
|
requestPath: "/api/setup-keys",
|
||||||
requestBody: &api.CreateSetupKeyRequest{
|
requestBody: &api.CreateSetupKeyRequest{
|
||||||
@@ -308,14 +306,15 @@ func Test_SetupKeys_Create(t *testing.T) {
|
|||||||
t.Fatalf("Sent content is not in correct json format; %v", err)
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gotID := got.Id
|
||||||
validateCreatedKey(t, tc.expectedResponse, got)
|
validateCreatedKey(t, tc.expectedResponse, got)
|
||||||
|
|
||||||
key, err := am.GetSetupKey(context.Background(), testing_tools.TestAccountId, testing_tools.TestUserId, got.Id)
|
// Verify setup key exists in DB via gorm
|
||||||
if err != nil {
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
return
|
dbKey := testing_tools.VerifySetupKeyInDB(t, db, gotID)
|
||||||
}
|
assert.Equal(t, tc.expectedResponse.Name, dbKey.Name)
|
||||||
|
assert.Equal(t, tc.expectedResponse.Revoked, dbKey.Revoked)
|
||||||
validateCreatedKey(t, tc.expectedResponse, setup_keys.ToResponseBody(key))
|
assert.Equal(t, tc.expectedResponse.UsageLimit, dbKey.UsageLimit)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
@@ -571,7 +570,7 @@ func Test_SetupKeys_Update(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range tt {
|
for _, tc := range tt {
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
apiHandler, am, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/setup_keys.sql", nil, true)
|
apiHandler, am, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/setup_keys.sql", nil, true)
|
||||||
|
|
||||||
body, err := json.Marshal(tc.requestBody)
|
body, err := json.Marshal(tc.requestBody)
|
||||||
@@ -594,14 +593,16 @@ func Test_SetupKeys_Update(t *testing.T) {
|
|||||||
t.Fatalf("Sent content is not in correct json format; %v", err)
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gotID := got.Id
|
||||||
|
gotRevoked := got.Revoked
|
||||||
|
gotUsageLimit := got.UsageLimit
|
||||||
validateCreatedKey(t, tc.expectedResponse, got)
|
validateCreatedKey(t, tc.expectedResponse, got)
|
||||||
|
|
||||||
key, err := am.GetSetupKey(context.Background(), testing_tools.TestAccountId, testing_tools.TestUserId, got.Id)
|
// Verify updated setup key in DB via gorm
|
||||||
if err != nil {
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
return
|
dbKey := testing_tools.VerifySetupKeyInDB(t, db, gotID)
|
||||||
}
|
assert.Equal(t, gotRevoked, dbKey.Revoked)
|
||||||
|
assert.Equal(t, gotUsageLimit, dbKey.UsageLimit)
|
||||||
validateCreatedKey(t, tc.expectedResponse, setup_keys.ToResponseBody(key))
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
@@ -759,8 +760,8 @@ func Test_SetupKeys_Get(t *testing.T) {
|
|||||||
|
|
||||||
apiHandler.ServeHTTP(recorder, req)
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
content, expectRespnose := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
if !expectRespnose {
|
if !expectResponse {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
got := &api.SetupKey{}
|
got := &api.SetupKey{}
|
||||||
@@ -768,14 +769,16 @@ func Test_SetupKeys_Get(t *testing.T) {
|
|||||||
t.Fatalf("Sent content is not in correct json format; %v", err)
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gotID := got.Id
|
||||||
|
gotName := got.Name
|
||||||
|
gotRevoked := got.Revoked
|
||||||
validateCreatedKey(t, tc.expectedResponse, got)
|
validateCreatedKey(t, tc.expectedResponse, got)
|
||||||
|
|
||||||
key, err := am.GetSetupKey(context.Background(), testing_tools.TestAccountId, testing_tools.TestUserId, got.Id)
|
// Verify setup key in DB via gorm
|
||||||
if err != nil {
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
return
|
dbKey := testing_tools.VerifySetupKeyInDB(t, db, gotID)
|
||||||
}
|
assert.Equal(t, gotName, dbKey.Name)
|
||||||
|
assert.Equal(t, gotRevoked, dbKey.Revoked)
|
||||||
validateCreatedKey(t, tc.expectedResponse, setup_keys.ToResponseBody(key))
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
@@ -928,15 +931,17 @@ func Test_SetupKeys_GetAll(t *testing.T) {
|
|||||||
return tc.expectedResponse[i].UsageLimit < tc.expectedResponse[j].UsageLimit
|
return tc.expectedResponse[i].UsageLimit < tc.expectedResponse[j].UsageLimit
|
||||||
})
|
})
|
||||||
|
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
for i := range tc.expectedResponse {
|
for i := range tc.expectedResponse {
|
||||||
|
gotID := got[i].Id
|
||||||
|
gotName := got[i].Name
|
||||||
|
gotRevoked := got[i].Revoked
|
||||||
validateCreatedKey(t, tc.expectedResponse[i], &got[i])
|
validateCreatedKey(t, tc.expectedResponse[i], &got[i])
|
||||||
|
|
||||||
key, err := am.GetSetupKey(context.Background(), testing_tools.TestAccountId, testing_tools.TestUserId, got[i].Id)
|
// Verify each setup key in DB via gorm
|
||||||
if err != nil {
|
dbKey := testing_tools.VerifySetupKeyInDB(t, db, gotID)
|
||||||
return
|
assert.Equal(t, gotName, dbKey.Name)
|
||||||
}
|
assert.Equal(t, gotRevoked, dbKey.Revoked)
|
||||||
|
|
||||||
validateCreatedKey(t, tc.expectedResponse[i], setup_keys.ToResponseBody(key))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -1104,8 +1109,9 @@ func Test_SetupKeys_Delete(t *testing.T) {
|
|||||||
t.Fatalf("Sent content is not in correct json format; %v", err)
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := am.GetSetupKey(context.Background(), testing_tools.TestAccountId, testing_tools.TestUserId, got.Id)
|
// Verify setup key deleted from DB via gorm
|
||||||
assert.Errorf(t, err, "Expected error when trying to get deleted key")
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
testing_tools.VerifySetupKeyNotInDB(t, db, got.Id)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-done:
|
case <-done:
|
||||||
@@ -1120,7 +1126,7 @@ func Test_SetupKeys_Delete(t *testing.T) {
|
|||||||
func validateCreatedKey(t *testing.T, expectedKey *api.SetupKey, got *api.SetupKey) {
|
func validateCreatedKey(t *testing.T, expectedKey *api.SetupKey, got *api.SetupKey) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
if got.Expires.After(time.Now().Add(-1*time.Minute)) && got.Expires.Before(time.Now().Add(testing_tools.ExpiresIn*time.Second)) ||
|
if (got.Expires.After(time.Now().Add(-1*time.Minute)) && got.Expires.Before(time.Now().Add(testing_tools.ExpiresIn*time.Second))) ||
|
||||||
got.Expires.After(time.Date(2300, 01, 01, 0, 0, 0, 0, time.Local)) ||
|
got.Expires.After(time.Date(2300, 01, 01, 0, 0, 0, 0, time.Local)) ||
|
||||||
got.Expires.Before(time.Date(1950, 01, 01, 0, 0, 0, 0, time.Local)) {
|
got.Expires.Before(time.Date(1950, 01, 01, 0, 0, 0, 0, time.Local)) {
|
||||||
got.Expires = time.Time{}
|
got.Expires = time.Time{}
|
||||||
|
|||||||
@@ -0,0 +1,701 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools"
|
||||||
|
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools/channel"
|
||||||
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Users_GetAll(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, true},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, true},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - Get all users", func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/users_integration.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, "/api/users", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, http.StatusOK, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := []api.User{}
|
||||||
|
if err := json.Unmarshal(content, &got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.GreaterOrEqual(t, len(got), 1)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Users_GetAll_ServiceUsers(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - Get all service users", func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/users_integration.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, "/api/users?service_user=true", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, http.StatusOK, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := []api.User{}
|
||||||
|
if err := json.Unmarshal(content, &got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, u := range got {
|
||||||
|
assert.NotNil(t, u.IsServiceUser)
|
||||||
|
assert.Equal(t, true, *u.IsServiceUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Users_Create_ServiceUser(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
requestBody *api.UserCreateRequest
|
||||||
|
expectedStatus int
|
||||||
|
verifyResponse func(t *testing.T, user *api.User)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Create service user with admin role",
|
||||||
|
requestBody: &api.UserCreateRequest{
|
||||||
|
Role: "admin",
|
||||||
|
IsServiceUser: true,
|
||||||
|
AutoGroups: []string{testing_tools.TestGroupId},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, user *api.User) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotEmpty(t, user.Id)
|
||||||
|
assert.Equal(t, "admin", user.Role)
|
||||||
|
assert.NotNil(t, user.IsServiceUser)
|
||||||
|
assert.Equal(t, true, *user.IsServiceUser)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create service user with user role",
|
||||||
|
requestBody: &api.UserCreateRequest{
|
||||||
|
Role: "user",
|
||||||
|
IsServiceUser: true,
|
||||||
|
AutoGroups: []string{testing_tools.TestGroupId},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, user *api.User) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotEmpty(t, user.Id)
|
||||||
|
assert.Equal(t, "user", user.Role)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create service user with empty auto_groups",
|
||||||
|
requestBody: &api.UserCreateRequest{
|
||||||
|
Role: "admin",
|
||||||
|
IsServiceUser: true,
|
||||||
|
AutoGroups: []string{},
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, user *api.User) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotEmpty(t, user.Id)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/users_integration.sql", nil, true)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPost, "/api/users", user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.User{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify user in DB
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbUser := testing_tools.VerifyUserInDB(t, db, got.Id)
|
||||||
|
assert.True(t, dbUser.IsServiceUser)
|
||||||
|
assert.Equal(t, string(dbUser.Role), string(tc.requestBody.Role))
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Users_Update(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
targetUserId string
|
||||||
|
requestBody *api.UserRequest
|
||||||
|
expectedStatus int
|
||||||
|
verifyResponse func(t *testing.T, user *api.User)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Update user role to admin",
|
||||||
|
targetUserId: testing_tools.TestUserId,
|
||||||
|
requestBody: &api.UserRequest{
|
||||||
|
Role: "admin",
|
||||||
|
AutoGroups: []string{},
|
||||||
|
IsBlocked: false,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, user *api.User) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, "admin", user.Role)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update user auto_groups",
|
||||||
|
targetUserId: testing_tools.TestUserId,
|
||||||
|
requestBody: &api.UserRequest{
|
||||||
|
Role: "user",
|
||||||
|
AutoGroups: []string{testing_tools.TestGroupId},
|
||||||
|
IsBlocked: false,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, user *api.User) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, 1, len(user.AutoGroups))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Block user",
|
||||||
|
targetUserId: testing_tools.TestUserId,
|
||||||
|
requestBody: &api.UserRequest{
|
||||||
|
Role: "user",
|
||||||
|
AutoGroups: []string{},
|
||||||
|
IsBlocked: true,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, user *api.User) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Equal(t, true, user.IsBlocked)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Update non-existing user",
|
||||||
|
targetUserId: "nonExistingUserId",
|
||||||
|
requestBody: &api.UserRequest{
|
||||||
|
Role: "user",
|
||||||
|
AutoGroups: []string{},
|
||||||
|
IsBlocked: false,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/users_integration.sql", nil, false)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPut, strings.Replace("/api/users/{userId}", "{userId}", tc.targetUserId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.User{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify updated fields in DB
|
||||||
|
if tc.expectedStatus == http.StatusOK {
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbUser := testing_tools.VerifyUserInDB(t, db, tc.targetUserId)
|
||||||
|
assert.Equal(t, string(dbUser.Role), string(tc.requestBody.Role))
|
||||||
|
assert.Equal(t, dbUser.Blocked, tc.requestBody.IsBlocked)
|
||||||
|
assert.ElementsMatch(t, dbUser.AutoGroups, tc.requestBody.AutoGroups)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Users_Delete(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
targetUserId string
|
||||||
|
expectedStatus int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Delete existing service user",
|
||||||
|
targetUserId: "deletableServiceUserId",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Delete non-existing user",
|
||||||
|
targetUserId: "nonExistingUserId",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/users_integration.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodDelete, strings.Replace("/api/users/{userId}", "{userId}", tc.targetUserId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
_, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
|
||||||
|
// Verify user deleted from DB for successful deletes
|
||||||
|
if expectResponse && tc.expectedStatus == http.StatusOK {
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
testing_tools.VerifyUserNotInDB(t, db, tc.targetUserId)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_PATs_GetAll(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - Get all PATs for service user", func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/users_integration.sql", nil, true)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, strings.Replace("/api/users/{userId}/tokens", "{userId}", testing_tools.TestServiceUserId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, http.StatusOK, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
got := []api.PersonalAccessToken{}
|
||||||
|
if err := json.Unmarshal(content, &got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 1, len(got))
|
||||||
|
assert.Equal(t, "serviceToken", got[0].Name)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_PATs_GetById(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
tokenId string
|
||||||
|
expectedStatus int
|
||||||
|
expectToken bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Get existing PAT",
|
||||||
|
tokenId: "serviceTokenId",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
expectToken: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Get non-existing PAT",
|
||||||
|
tokenId: "nonExistingTokenId",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
expectToken: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, _, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/users_integration.sql", nil, true)
|
||||||
|
|
||||||
|
path := strings.Replace("/api/users/{userId}/tokens/{tokenId}", "{userId}", testing_tools.TestServiceUserId, 1)
|
||||||
|
path = strings.Replace(path, "{tokenId}", tc.tokenId, 1)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodGet, path, user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.expectToken {
|
||||||
|
got := &api.PersonalAccessToken{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, "serviceTokenId", got.Id)
|
||||||
|
assert.Equal(t, "serviceToken", got.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_PATs_Create(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
targetUserId string
|
||||||
|
requestBody *api.PersonalAccessTokenRequest
|
||||||
|
expectedStatus int
|
||||||
|
verifyResponse func(t *testing.T, pat *api.PersonalAccessTokenGenerated)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Create PAT with 30 day expiry",
|
||||||
|
targetUserId: testing_tools.TestServiceUserId,
|
||||||
|
requestBody: &api.PersonalAccessTokenRequest{
|
||||||
|
Name: "newPAT",
|
||||||
|
ExpiresIn: 30,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, pat *api.PersonalAccessTokenGenerated) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotEmpty(t, pat.PlainToken)
|
||||||
|
assert.Equal(t, "newPAT", pat.PersonalAccessToken.Name)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create PAT with 365 day expiry",
|
||||||
|
targetUserId: testing_tools.TestServiceUserId,
|
||||||
|
requestBody: &api.PersonalAccessTokenRequest{
|
||||||
|
Name: "longPAT",
|
||||||
|
ExpiresIn: 365,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
verifyResponse: func(t *testing.T, pat *api.PersonalAccessTokenGenerated) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotEmpty(t, pat.PlainToken)
|
||||||
|
assert.Equal(t, "longPAT", pat.PersonalAccessToken.Name)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create PAT with empty name",
|
||||||
|
targetUserId: testing_tools.TestServiceUserId,
|
||||||
|
requestBody: &api.PersonalAccessTokenRequest{
|
||||||
|
Name: "",
|
||||||
|
ExpiresIn: 30,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create PAT with 0 day expiry",
|
||||||
|
targetUserId: testing_tools.TestServiceUserId,
|
||||||
|
requestBody: &api.PersonalAccessTokenRequest{
|
||||||
|
Name: "zeroPAT",
|
||||||
|
ExpiresIn: 0,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Create PAT with expiry over 365 days",
|
||||||
|
targetUserId: testing_tools.TestServiceUserId,
|
||||||
|
requestBody: &api.PersonalAccessTokenRequest{
|
||||||
|
Name: "tooLongPAT",
|
||||||
|
ExpiresIn: 400,
|
||||||
|
},
|
||||||
|
expectedStatus: http.StatusUnprocessableEntity,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/users_integration.sql", nil, true)
|
||||||
|
|
||||||
|
body, err := json.Marshal(tc.requestBody)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to marshal request body: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, body, http.MethodPost, strings.Replace("/api/users/{userId}/tokens", "{userId}", tc.targetUserId, 1), user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
content, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
if !expectResponse {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.verifyResponse != nil {
|
||||||
|
got := &api.PersonalAccessTokenGenerated{}
|
||||||
|
if err := json.Unmarshal(content, got); err != nil {
|
||||||
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
||||||
|
}
|
||||||
|
tc.verifyResponse(t, got)
|
||||||
|
|
||||||
|
// Verify PAT in DB
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
dbPAT := testing_tools.VerifyPATInDB(t, db, got.PersonalAccessToken.Id)
|
||||||
|
assert.Equal(t, tc.requestBody.Name, dbPAT.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_PATs_Delete(t *testing.T) {
|
||||||
|
users := []struct {
|
||||||
|
name string
|
||||||
|
userId string
|
||||||
|
expectResponse bool
|
||||||
|
}{
|
||||||
|
{"Regular user", testing_tools.TestUserId, false},
|
||||||
|
{"Admin user", testing_tools.TestAdminId, true},
|
||||||
|
{"Owner user", testing_tools.TestOwnerId, true},
|
||||||
|
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||||
|
{"Admin service user", testing_tools.TestServiceAdminId, true},
|
||||||
|
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||||
|
{"Other user", testing_tools.OtherUserId, false},
|
||||||
|
{"Invalid token", testing_tools.InvalidToken, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
tokenId string
|
||||||
|
expectedStatus int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Delete existing PAT",
|
||||||
|
tokenId: "serviceTokenId",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Delete non-existing PAT",
|
||||||
|
tokenId: "nonExistingTokenId",
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
for _, user := range users {
|
||||||
|
t.Run(user.name+" - "+tc.name, func(t *testing.T) {
|
||||||
|
apiHandler, am, done := channel.BuildApiBlackBoxWithDBState(t, "../testdata/users_integration.sql", nil, true)
|
||||||
|
|
||||||
|
path := strings.Replace("/api/users/{userId}/tokens/{tokenId}", "{userId}", testing_tools.TestServiceUserId, 1)
|
||||||
|
path = strings.Replace(path, "{tokenId}", tc.tokenId, 1)
|
||||||
|
|
||||||
|
req := testing_tools.BuildRequest(t, []byte{}, http.MethodDelete, path, user.userId)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
apiHandler.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
_, expectResponse := testing_tools.ReadResponse(t, recorder, tc.expectedStatus, user.expectResponse)
|
||||||
|
|
||||||
|
// Verify PAT deleted from DB for successful deletes
|
||||||
|
if expectResponse && tc.expectedStatus == http.StatusOK {
|
||||||
|
db := testing_tools.GetDB(t, am.GetStore())
|
||||||
|
testing_tools.VerifyPATNotInDB(t, db, tc.tokenId)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
management/server/http/testing/testdata/accounts.sql
vendored
Normal file
18
management/server/http/testing/testdata/accounts.sql
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
CREATE TABLE `accounts` (`id` text,`created_by` text,`created_at` datetime,`domain` text,`domain_category` text,`is_domain_primary_account` numeric,`network_identifier` text,`network_net` text,`network_dns` text,`network_serial` integer,`dns_settings_disabled_management_groups` text,`settings_peer_login_expiration_enabled` numeric,`settings_peer_login_expiration` integer,`settings_regular_users_view_blocked` numeric,`settings_groups_propagation_enabled` numeric,`settings_jwt_groups_enabled` numeric,`settings_jwt_groups_claim_name` text,`settings_jwt_allow_groups` text,`settings_extra_peer_approval_enabled` numeric,`settings_extra_integrated_validator_groups` text,PRIMARY KEY (`id`));
|
||||||
|
CREATE TABLE `users` (`id` text,`account_id` text,`role` text,`is_service_user` numeric,`non_deletable` numeric,`service_user_name` text,`auto_groups` text,`blocked` numeric,`last_login` datetime DEFAULT NULL,`created_at` datetime,`issued` text DEFAULT "api",`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_users_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `groups` (`id` text,`account_id` text,`name` text,`issued` text,`peers` text,`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_groups_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `peers` (`id` text,`account_id` text,`key` text,`setup_key` text,`ip` text,`meta_hostname` text,`meta_go_os` text,`meta_kernel` text,`meta_core` text,`meta_platform` text,`meta_os` text,`meta_os_version` text,`meta_wt_version` text,`meta_ui_version` text,`meta_kernel_version` text,`meta_network_addresses` text,`meta_system_serial_number` text,`meta_system_product_name` text,`meta_system_manufacturer` text,`meta_environment` text,`meta_files` text,`name` text,`dns_label` text,`peer_status_last_seen` datetime,`peer_status_connected` numeric,`peer_status_login_expired` numeric,`peer_status_requires_approval` numeric,`user_id` text,`ssh_key` text,`ssh_enabled` numeric,`login_expiration_enabled` numeric,`last_login` datetime,`created_at` datetime,`ephemeral` numeric,`location_connection_ip` text,`location_country_code` text,`location_city_name` text,`location_geo_name_id` integer,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_peers_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `setup_keys` (`id` text,`account_id` text,`key` text,`key_secret` text,`name` text,`type` text,`created_at` datetime,`expires_at` datetime,`updated_at` datetime,`revoked` numeric,`used_times` integer,`last_used` datetime DEFAULT NULL,`auto_groups` text,`usage_limit` integer,`ephemeral` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_setup_keys_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
|
||||||
|
INSERT INTO accounts VALUES('testAccountId','','2024-10-02 16:01:38.000000000+00:00','test.com','private',1,'testNetworkIdentifier','{"IP":"100.64.0.0","Mask":"//8AAA=="}','',0,'[]',1,86400000000000,0,0,0,'',NULL,NULL,NULL);
|
||||||
|
INSERT INTO users VALUES('testUserId','testAccountId','user',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testAdminId','testAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testOwnerId','testAccountId','owner',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceUserId','testAccountId','user',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceAdminId','testAccountId','admin',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('blockedUserId','testAccountId','admin',0,0,'','[]',1,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('otherUserId','otherAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('testGroupId','testAccountId','testGroupName','api','[]',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('newGroupId','testAccountId','newGroupName','api','[]',0,'');
|
||||||
|
INSERT INTO peers VALUES('testPeerId','testAccountId','5rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYAg=','72546A29-6BC8-4311-BCFC-9CDBF33F1A48','"100.64.114.31"','f2a34f6a4731','linux','Linux','11','unknown','Debian GNU/Linux','','0.12.0','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'f2a34f6a4731','f2a34f6a4731','2023-03-02 09:21:02.189035775+01:00',0,0,0,'','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk',0,1,'2023-03-01 19:48:19.817799698+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
|
INSERT INTO setup_keys VALUES('testKeyId','testAccountId','testKey','testK****','existingKey','one-off','2021-08-19 20:46:20.000000000+00:00','2321-09-18 20:46:20.000000000+00:00','2021-08-19 20:46:20.000000000+00:000',0,0,NULL,'["testGroupId"]',1,0);
|
||||||
21
management/server/http/testing/testdata/dns.sql
vendored
Normal file
21
management/server/http/testing/testdata/dns.sql
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
CREATE TABLE `accounts` (`id` text,`created_by` text,`created_at` datetime,`domain` text,`domain_category` text,`is_domain_primary_account` numeric,`network_identifier` text,`network_net` text,`network_dns` text,`network_serial` integer,`dns_settings_disabled_management_groups` text,`settings_peer_login_expiration_enabled` numeric,`settings_peer_login_expiration` integer,`settings_regular_users_view_blocked` numeric,`settings_groups_propagation_enabled` numeric,`settings_jwt_groups_enabled` numeric,`settings_jwt_groups_claim_name` text,`settings_jwt_allow_groups` text,`settings_extra_peer_approval_enabled` numeric,`settings_extra_integrated_validator_groups` text,PRIMARY KEY (`id`));
|
||||||
|
CREATE TABLE `users` (`id` text,`account_id` text,`role` text,`is_service_user` numeric,`non_deletable` numeric,`service_user_name` text,`auto_groups` text,`blocked` numeric,`last_login` datetime DEFAULT NULL,`created_at` datetime,`issued` text DEFAULT "api",`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_users_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `groups` (`id` text,`account_id` text,`name` text,`issued` text,`peers` text,`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_groups_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `setup_keys` (`id` text,`account_id` text,`key` text,`key_secret` text,`name` text,`type` text,`created_at` datetime,`expires_at` datetime,`updated_at` datetime,`revoked` numeric,`used_times` integer,`last_used` datetime DEFAULT NULL,`auto_groups` text,`usage_limit` integer,`ephemeral` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_setup_keys_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `peers` (`id` text,`account_id` text,`key` text,`setup_key` text,`ip` text,`meta_hostname` text,`meta_go_os` text,`meta_kernel` text,`meta_core` text,`meta_platform` text,`meta_os` text,`meta_os_version` text,`meta_wt_version` text,`meta_ui_version` text,`meta_kernel_version` text,`meta_network_addresses` text,`meta_system_serial_number` text,`meta_system_product_name` text,`meta_system_manufacturer` text,`meta_environment` text,`meta_files` text,`name` text,`dns_label` text,`peer_status_last_seen` datetime,`peer_status_connected` numeric,`peer_status_login_expired` numeric,`peer_status_requires_approval` numeric,`user_id` text,`ssh_key` text,`ssh_enabled` numeric,`login_expiration_enabled` numeric,`last_login` datetime,`created_at` datetime,`ephemeral` numeric,`location_connection_ip` text,`location_country_code` text,`location_city_name` text,`location_geo_name_id` integer,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_peers_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `name_server_groups` (`id` text,`account_id` text,`name` text,`description` text,`name_servers` text,`groups` text,`primary` numeric,`domains` text,`enabled` numeric,`search_domains_enabled` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_name_server_groups_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
|
||||||
|
INSERT INTO accounts VALUES('testAccountId','','2024-10-02 16:01:38.000000000+00:00','test.com','private',1,'testNetworkIdentifier','{"IP":"100.64.0.0","Mask":"//8AAA=="}','',0,'[]',1,86400000000000,0,0,0,'',NULL,NULL,NULL);
|
||||||
|
INSERT INTO users VALUES('testUserId','testAccountId','user',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testAdminId','testAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testOwnerId','testAccountId','owner',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceUserId','testAccountId','user',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceAdminId','testAccountId','admin',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('blockedUserId','testAccountId','admin',0,0,'','[]',1,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('otherUserId','otherAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('testGroupId','testAccountId','testGroupName','api','["testPeerId"]',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('newGroupId','testAccountId','newGroupName','api','[]',0,'');
|
||||||
|
INSERT INTO setup_keys VALUES('testKeyId','testAccountId','testKey','testK****','existingKey','one-off','2021-08-19 20:46:20.000000000+00:00','2321-09-18 20:46:20.000000000+00:00','2021-08-19 20:46:20.000000000+00:000',0,0,NULL,'["testGroupId"]',1,0);
|
||||||
|
INSERT INTO peers VALUES('testPeerId','testAccountId','5rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYAg=','72546A29-6BC8-4311-BCFC-9CDBF33F1A48','"100.64.114.31"','f2a34f6a4731','linux','Linux','11','unknown','Debian GNU/Linux','','0.12.0','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'f2a34f6a4731','f2a34f6a4731','2023-03-02 09:21:02.189035775+01:00',0,0,0,'','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk',0,1,'2023-03-01 19:48:19.817799698+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
|
|
||||||
|
INSERT INTO name_server_groups VALUES('testNSGroupId','testAccountId','testNSGroup','test nameserver group','[{"IP":"1.1.1.1","NSType":1,"Port":53}]','["testGroupId"]',0,'["example.com"]',1,0);
|
||||||
18
management/server/http/testing/testdata/events.sql
vendored
Normal file
18
management/server/http/testing/testdata/events.sql
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
CREATE TABLE `accounts` (`id` text,`created_by` text,`created_at` datetime,`domain` text,`domain_category` text,`is_domain_primary_account` numeric,`network_identifier` text,`network_net` text,`network_dns` text,`network_serial` integer,`dns_settings_disabled_management_groups` text,`settings_peer_login_expiration_enabled` numeric,`settings_peer_login_expiration` integer,`settings_regular_users_view_blocked` numeric,`settings_groups_propagation_enabled` numeric,`settings_jwt_groups_enabled` numeric,`settings_jwt_groups_claim_name` text,`settings_jwt_allow_groups` text,`settings_extra_peer_approval_enabled` numeric,`settings_extra_integrated_validator_groups` text,PRIMARY KEY (`id`));
|
||||||
|
CREATE TABLE `users` (`id` text,`account_id` text,`role` text,`is_service_user` numeric,`non_deletable` numeric,`service_user_name` text,`auto_groups` text,`blocked` numeric,`last_login` datetime DEFAULT NULL,`created_at` datetime,`issued` text DEFAULT "api",`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_users_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `groups` (`id` text,`account_id` text,`name` text,`issued` text,`peers` text,`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_groups_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `setup_keys` (`id` text,`account_id` text,`key` text,`key_secret` text,`name` text,`type` text,`created_at` datetime,`expires_at` datetime,`updated_at` datetime,`revoked` numeric,`used_times` integer,`last_used` datetime DEFAULT NULL,`auto_groups` text,`usage_limit` integer,`ephemeral` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_setup_keys_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `peers` (`id` text,`account_id` text,`key` text,`setup_key` text,`ip` text,`meta_hostname` text,`meta_go_os` text,`meta_kernel` text,`meta_core` text,`meta_platform` text,`meta_os` text,`meta_os_version` text,`meta_wt_version` text,`meta_ui_version` text,`meta_kernel_version` text,`meta_network_addresses` text,`meta_system_serial_number` text,`meta_system_product_name` text,`meta_system_manufacturer` text,`meta_environment` text,`meta_files` text,`name` text,`dns_label` text,`peer_status_last_seen` datetime,`peer_status_connected` numeric,`peer_status_login_expired` numeric,`peer_status_requires_approval` numeric,`user_id` text,`ssh_key` text,`ssh_enabled` numeric,`login_expiration_enabled` numeric,`last_login` datetime,`created_at` datetime,`ephemeral` numeric,`location_connection_ip` text,`location_country_code` text,`location_city_name` text,`location_geo_name_id` integer,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_peers_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
|
||||||
|
INSERT INTO accounts VALUES('testAccountId','','2024-10-02 16:01:38.000000000+00:00','test.com','private',1,'testNetworkIdentifier','{"IP":"100.64.0.0","Mask":"//8AAA=="}','',0,'[]',1,86400000000000,0,0,0,'',NULL,NULL,NULL);
|
||||||
|
INSERT INTO users VALUES('testUserId','testAccountId','user',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testAdminId','testAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testOwnerId','testAccountId','owner',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceUserId','testAccountId','user',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceAdminId','testAccountId','admin',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('blockedUserId','testAccountId','admin',0,0,'','[]',1,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('otherUserId','otherAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('testGroupId','testAccountId','testGroupName','api','[]',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('newGroupId','testAccountId','newGroupName','api','[]',0,'');
|
||||||
|
INSERT INTO setup_keys VALUES('testKeyId','testAccountId','testKey','testK****','existingKey','one-off','2021-08-19 20:46:20.000000000+00:00','2321-09-18 20:46:20.000000000+00:00','2021-08-19 20:46:20.000000000+00:000',0,0,NULL,'["testGroupId"]',1,0);
|
||||||
|
INSERT INTO peers VALUES('testPeerId','testAccountId','5rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYAg=','72546A29-6BC8-4311-BCFC-9CDBF33F1A48','"100.64.114.31"','f2a34f6a4731','linux','Linux','11','unknown','Debian GNU/Linux','','0.12.0','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'f2a34f6a4731','f2a34f6a4731','2023-03-02 09:21:02.189035775+01:00',0,0,0,'','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk',0,1,'2023-03-01 19:48:19.817799698+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
19
management/server/http/testing/testdata/groups.sql
vendored
Normal file
19
management/server/http/testing/testdata/groups.sql
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
CREATE TABLE `accounts` (`id` text,`created_by` text,`created_at` datetime,`domain` text,`domain_category` text,`is_domain_primary_account` numeric,`network_identifier` text,`network_net` text,`network_dns` text,`network_serial` integer,`dns_settings_disabled_management_groups` text,`settings_peer_login_expiration_enabled` numeric,`settings_peer_login_expiration` integer,`settings_regular_users_view_blocked` numeric,`settings_groups_propagation_enabled` numeric,`settings_jwt_groups_enabled` numeric,`settings_jwt_groups_claim_name` text,`settings_jwt_allow_groups` text,`settings_extra_peer_approval_enabled` numeric,`settings_extra_integrated_validator_groups` text,PRIMARY KEY (`id`));
|
||||||
|
CREATE TABLE `users` (`id` text,`account_id` text,`role` text,`is_service_user` numeric,`non_deletable` numeric,`service_user_name` text,`auto_groups` text,`blocked` numeric,`last_login` datetime DEFAULT NULL,`created_at` datetime,`issued` text DEFAULT "api",`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_users_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `groups` (`id` text,`account_id` text,`name` text,`issued` text,`peers` text,`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_groups_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `setup_keys` (`id` text,`account_id` text,`key` text,`key_secret` text,`name` text,`type` text,`created_at` datetime,`expires_at` datetime,`updated_at` datetime,`revoked` numeric,`used_times` integer,`last_used` datetime DEFAULT NULL,`auto_groups` text,`usage_limit` integer,`ephemeral` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_setup_keys_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `peers` (`id` text,`account_id` text,`key` text,`setup_key` text,`ip` text,`meta_hostname` text,`meta_go_os` text,`meta_kernel` text,`meta_core` text,`meta_platform` text,`meta_os` text,`meta_os_version` text,`meta_wt_version` text,`meta_ui_version` text,`meta_kernel_version` text,`meta_network_addresses` text,`meta_system_serial_number` text,`meta_system_product_name` text,`meta_system_manufacturer` text,`meta_environment` text,`meta_files` text,`name` text,`dns_label` text,`peer_status_last_seen` datetime,`peer_status_connected` numeric,`peer_status_login_expired` numeric,`peer_status_requires_approval` numeric,`user_id` text,`ssh_key` text,`ssh_enabled` numeric,`login_expiration_enabled` numeric,`last_login` datetime,`created_at` datetime,`ephemeral` numeric,`location_connection_ip` text,`location_country_code` text,`location_city_name` text,`location_geo_name_id` integer,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_peers_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
|
||||||
|
INSERT INTO accounts VALUES('testAccountId','','2024-10-02 16:01:38.000000000+00:00','test.com','private',1,'testNetworkIdentifier','{"IP":"100.64.0.0","Mask":"//8AAA=="}','',0,'[]',1,86400000000000,0,0,0,'',NULL,NULL,NULL);
|
||||||
|
INSERT INTO users VALUES('testUserId','testAccountId','user',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testAdminId','testAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testOwnerId','testAccountId','owner',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceUserId','testAccountId','user',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceAdminId','testAccountId','admin',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('blockedUserId','testAccountId','admin',0,0,'','[]',1,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('otherUserId','otherAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('testGroupId','testAccountId','testGroupName','api','["testPeerId"]',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('newGroupId','testAccountId','newGroupName','api','[]',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('allGroupId','testAccountId','All','api','[]',0,'');
|
||||||
|
INSERT INTO setup_keys VALUES('testKeyId','testAccountId','testKey','testK****','existingKey','one-off','2021-08-19 20:46:20.000000000+00:00','2321-09-18 20:46:20.000000000+00:00','2021-08-19 20:46:20.000000000+00:000',0,0,NULL,'["testGroupId"]',1,0);
|
||||||
|
INSERT INTO peers VALUES('testPeerId','testAccountId','5rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYAg=','72546A29-6BC8-4311-BCFC-9CDBF33F1A48','"100.64.114.31"','f2a34f6a4731','linux','Linux','11','unknown','Debian GNU/Linux','','0.12.0','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'f2a34f6a4731','f2a34f6a4731','2023-03-02 09:21:02.189035775+01:00',0,0,0,'','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk',0,1,'2023-03-01 19:48:19.817799698+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
25
management/server/http/testing/testdata/networks.sql
vendored
Normal file
25
management/server/http/testing/testdata/networks.sql
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
CREATE TABLE `accounts` (`id` text,`created_by` text,`created_at` datetime,`domain` text,`domain_category` text,`is_domain_primary_account` numeric,`network_identifier` text,`network_net` text,`network_dns` text,`network_serial` integer,`dns_settings_disabled_management_groups` text,`settings_peer_login_expiration_enabled` numeric,`settings_peer_login_expiration` integer,`settings_regular_users_view_blocked` numeric,`settings_groups_propagation_enabled` numeric,`settings_jwt_groups_enabled` numeric,`settings_jwt_groups_claim_name` text,`settings_jwt_allow_groups` text,`settings_extra_peer_approval_enabled` numeric,`settings_extra_integrated_validator_groups` text,PRIMARY KEY (`id`));
|
||||||
|
CREATE TABLE `users` (`id` text,`account_id` text,`role` text,`is_service_user` numeric,`non_deletable` numeric,`service_user_name` text,`auto_groups` text,`blocked` numeric,`last_login` datetime DEFAULT NULL,`created_at` datetime,`issued` text DEFAULT "api",`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_users_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `groups` (`id` text,`account_id` text,`name` text,`issued` text,`peers` text,`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_groups_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `setup_keys` (`id` text,`account_id` text,`key` text,`key_secret` text,`name` text,`type` text,`created_at` datetime,`expires_at` datetime,`updated_at` datetime,`revoked` numeric,`used_times` integer,`last_used` datetime DEFAULT NULL,`auto_groups` text,`usage_limit` integer,`ephemeral` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_setup_keys_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `peers` (`id` text,`account_id` text,`key` text,`setup_key` text,`ip` text,`meta_hostname` text,`meta_go_os` text,`meta_kernel` text,`meta_core` text,`meta_platform` text,`meta_os` text,`meta_os_version` text,`meta_wt_version` text,`meta_ui_version` text,`meta_kernel_version` text,`meta_network_addresses` text,`meta_system_serial_number` text,`meta_system_product_name` text,`meta_system_manufacturer` text,`meta_environment` text,`meta_files` text,`name` text,`dns_label` text,`peer_status_last_seen` datetime,`peer_status_connected` numeric,`peer_status_login_expired` numeric,`peer_status_requires_approval` numeric,`user_id` text,`ssh_key` text,`ssh_enabled` numeric,`login_expiration_enabled` numeric,`last_login` datetime,`created_at` datetime,`ephemeral` numeric,`location_connection_ip` text,`location_country_code` text,`location_city_name` text,`location_geo_name_id` integer,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_peers_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `networks` (`id` text,`account_id` text,`name` text,`description` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_networks` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `network_routers` (`id` text,`network_id` text,`account_id` text,`peer` text,`peer_groups` text,`masquerade` numeric,`metric` integer,`enabled` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_network_routers` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `network_resources` (`id` text,`network_id` text,`account_id` text,`name` text,`description` text,`type` text,`domain` text,`prefix` text,`enabled` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_network_resources` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
|
||||||
|
INSERT INTO accounts VALUES('testAccountId','','2024-10-02 16:01:38.000000000+00:00','test.com','private',1,'testNetworkIdentifier','{"IP":"100.64.0.0","Mask":"//8AAA=="}','',0,'[]',1,86400000000000,0,0,0,'',NULL,NULL,NULL);
|
||||||
|
INSERT INTO users VALUES('testUserId','testAccountId','user',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testAdminId','testAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testOwnerId','testAccountId','owner',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceUserId','testAccountId','user',1,0,'testServiceUser','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceAdminId','testAccountId','admin',1,0,'testServiceAdmin','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('blockedUserId','testAccountId','admin',0,0,'','[]',1,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('otherUserId','otherAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('testGroupId','testAccountId','testGroupName','api','["testPeerId"]',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('newGroupId','testAccountId','newGroupName','api','[]',0,'');
|
||||||
|
INSERT INTO setup_keys VALUES('testKeyId','testAccountId','testKey','testK****','existingKey','one-off','2021-08-19 20:46:20.000000000+00:00','2321-09-18 20:46:20.000000000+00:00','2021-08-19 20:46:20.000000000+00:00',0,0,NULL,'["testGroupId"]',1,0);
|
||||||
|
INSERT INTO peers VALUES('testPeerId','testAccountId','5rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYAg=','72546A29-6BC8-4311-BCFC-9CDBF33F1A48','"100.64.114.31"','f2a34f6a4731','linux','Linux','11','unknown','Debian GNU/Linux','','0.12.0','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'f2a34f6a4731','f2a34f6a4731','2023-03-02 09:21:02.189035775+01:00',0,0,0,'','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk',0,1,'2023-03-01 19:48:19.817799698+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
|
|
||||||
|
INSERT INTO networks VALUES('testNetworkId','testAccountId','testNetwork','test network description');
|
||||||
|
INSERT INTO network_routers VALUES('testRouterId','testNetworkId','testAccountId','testPeerId','[]',1,100,1);
|
||||||
|
INSERT INTO network_resources VALUES('testResourceId','testNetworkId','testAccountId','testResource','test resource description','host','','"3.3.3.3/32"',1);
|
||||||
20
management/server/http/testing/testdata/peers_integration.sql
vendored
Normal file
20
management/server/http/testing/testdata/peers_integration.sql
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
CREATE TABLE `accounts` (`id` text,`created_by` text,`created_at` datetime,`domain` text,`domain_category` text,`is_domain_primary_account` numeric,`network_identifier` text,`network_net` text,`network_dns` text,`network_serial` integer,`dns_settings_disabled_management_groups` text,`settings_peer_login_expiration_enabled` numeric,`settings_peer_login_expiration` integer,`settings_regular_users_view_blocked` numeric,`settings_groups_propagation_enabled` numeric,`settings_jwt_groups_enabled` numeric,`settings_jwt_groups_claim_name` text,`settings_jwt_allow_groups` text,`settings_extra_peer_approval_enabled` numeric,`settings_extra_integrated_validator_groups` text,PRIMARY KEY (`id`));
|
||||||
|
CREATE TABLE `users` (`id` text,`account_id` text,`role` text,`is_service_user` numeric,`non_deletable` numeric,`service_user_name` text,`auto_groups` text,`blocked` numeric,`last_login` datetime DEFAULT NULL,`created_at` datetime,`issued` text DEFAULT "api",`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_users_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `groups` (`id` text,`account_id` text,`name` text,`issued` text,`peers` text,`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_groups_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `setup_keys` (`id` text,`account_id` text,`key` text,`key_secret` text,`name` text,`type` text,`created_at` datetime,`expires_at` datetime,`updated_at` datetime,`revoked` numeric,`used_times` integer,`last_used` datetime DEFAULT NULL,`auto_groups` text,`usage_limit` integer,`ephemeral` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_setup_keys_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `peers` (`id` text,`account_id` text,`key` text,`setup_key` text,`ip` text,`meta_hostname` text,`meta_go_os` text,`meta_kernel` text,`meta_core` text,`meta_platform` text,`meta_os` text,`meta_os_version` text,`meta_wt_version` text,`meta_ui_version` text,`meta_kernel_version` text,`meta_network_addresses` text,`meta_system_serial_number` text,`meta_system_product_name` text,`meta_system_manufacturer` text,`meta_environment` text,`meta_files` text,`name` text,`dns_label` text,`peer_status_last_seen` datetime,`peer_status_connected` numeric,`peer_status_login_expired` numeric,`peer_status_requires_approval` numeric,`user_id` text,`ssh_key` text,`ssh_enabled` numeric,`login_expiration_enabled` numeric,`last_login` datetime,`created_at` datetime,`ephemeral` numeric,`location_connection_ip` text,`location_country_code` text,`location_city_name` text,`location_geo_name_id` integer,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_peers_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
|
||||||
|
INSERT INTO accounts VALUES('testAccountId','','2024-10-02 16:01:38.000000000+00:00','test.com','private',1,'testNetworkIdentifier','{"IP":"100.64.0.0","Mask":"//8AAA=="}','',0,'[]',0,86400000000000,0,0,0,'',NULL,NULL,NULL);
|
||||||
|
INSERT INTO users VALUES('testUserId','testAccountId','user',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testAdminId','testAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testOwnerId','testAccountId','owner',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceUserId','testAccountId','user',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceAdminId','testAccountId','admin',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('blockedUserId','testAccountId','admin',0,0,'','[]',1,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('otherUserId','otherAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('testGroupId','testAccountId','testGroupName','api','["testPeerId","testPeerId2"]',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('newGroupId','testAccountId','newGroupName','api','[]',0,'');
|
||||||
|
INSERT INTO setup_keys VALUES('testKeyId','testAccountId','testKey','testK****','existingKey','one-off','2021-08-19 20:46:20.000000000+00:00','2321-09-18 20:46:20.000000000+00:00','2021-08-19 20:46:20.000000000+00:000',0,0,NULL,'["testGroupId"]',1,0);
|
||||||
|
|
||||||
|
INSERT INTO peers VALUES('testPeerId','testAccountId','5rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYAg=','72546A29-6BC8-4311-BCFC-9CDBF33F1A48','"100.64.114.31"','test-host-1','linux','Linux','','unknown','Debian GNU/Linux','','0.12.0','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'test-peer-1','test-peer-1','2023-03-02 09:21:02.189035775+01:00',0,0,0,'testUserId','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk',0,1,'2023-03-01 19:48:19.817799698+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
|
INSERT INTO peers VALUES('testPeerId2','testAccountId','6rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYBg=','82546A29-6BC8-4311-BCFC-9CDBF33F1A49','"100.64.114.32"','test-host-2','linux','Linux','','unknown','Ubuntu','','0.12.0','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'test-peer-2','test-peer-2','2023-03-02 09:21:02.189035775+01:00',1,0,0,'testAdminId','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk',1,0,'2023-03-01 19:48:19.817799698+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
23
management/server/http/testing/testdata/policies.sql
vendored
Normal file
23
management/server/http/testing/testdata/policies.sql
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
CREATE TABLE `accounts` (`id` text,`created_by` text,`created_at` datetime,`domain` text,`domain_category` text,`is_domain_primary_account` numeric,`network_identifier` text,`network_net` text,`network_dns` text,`network_serial` integer,`dns_settings_disabled_management_groups` text,`settings_peer_login_expiration_enabled` numeric,`settings_peer_login_expiration` integer,`settings_regular_users_view_blocked` numeric,`settings_groups_propagation_enabled` numeric,`settings_jwt_groups_enabled` numeric,`settings_jwt_groups_claim_name` text,`settings_jwt_allow_groups` text,`settings_extra_peer_approval_enabled` numeric,`settings_extra_integrated_validator_groups` text,PRIMARY KEY (`id`));
|
||||||
|
CREATE TABLE `users` (`id` text,`account_id` text,`role` text,`is_service_user` numeric,`non_deletable` numeric,`service_user_name` text,`auto_groups` text,`blocked` numeric,`last_login` datetime DEFAULT NULL,`created_at` datetime,`issued` text DEFAULT "api",`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_users_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `groups` (`id` text,`account_id` text,`name` text,`issued` text,`peers` text,`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_groups_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `setup_keys` (`id` text,`account_id` text,`key` text,`key_secret` text,`name` text,`type` text,`created_at` datetime,`expires_at` datetime,`updated_at` datetime,`revoked` numeric,`used_times` integer,`last_used` datetime DEFAULT NULL,`auto_groups` text,`usage_limit` integer,`ephemeral` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_setup_keys_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `peers` (`id` text,`account_id` text,`key` text,`setup_key` text,`ip` text,`meta_hostname` text,`meta_go_os` text,`meta_kernel` text,`meta_core` text,`meta_platform` text,`meta_os` text,`meta_os_version` text,`meta_wt_version` text,`meta_ui_version` text,`meta_kernel_version` text,`meta_network_addresses` text,`meta_system_serial_number` text,`meta_system_product_name` text,`meta_system_manufacturer` text,`meta_environment` text,`meta_files` text,`name` text,`dns_label` text,`peer_status_last_seen` datetime,`peer_status_connected` numeric,`peer_status_login_expired` numeric,`peer_status_requires_approval` numeric,`user_id` text,`ssh_key` text,`ssh_enabled` numeric,`login_expiration_enabled` numeric,`last_login` datetime,`created_at` datetime,`ephemeral` numeric,`location_connection_ip` text,`location_country_code` text,`location_city_name` text,`location_geo_name_id` integer,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_peers_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `policies` (`id` text,`account_id` text,`name` text,`description` text,`enabled` numeric,`source_posture_checks` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_policies_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `policy_rules` (`id` text,`policy_id` text,`name` text,`description` text,`enabled` numeric,`action` text,`protocol` text,`bidirectional` numeric,`sources` text,`destinations` text,`source_resource` text,`destination_resource` text,`ports` text,`port_ranges` text,`authorized_groups` text,`authorized_user` text,PRIMARY KEY (`id`),CONSTRAINT `fk_policies_rules_g` FOREIGN KEY (`policy_id`) REFERENCES `policies`(`id`));
|
||||||
|
|
||||||
|
INSERT INTO accounts VALUES('testAccountId','','2024-10-02 16:01:38.000000000+00:00','test.com','private',1,'testNetworkIdentifier','{"IP":"100.64.0.0","Mask":"//8AAA=="}','',0,'[]',1,86400000000000,0,0,0,'',NULL,NULL,NULL);
|
||||||
|
INSERT INTO users VALUES('testUserId','testAccountId','user',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testAdminId','testAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testOwnerId','testAccountId','owner',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceUserId','testAccountId','user',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceAdminId','testAccountId','admin',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('blockedUserId','testAccountId','admin',0,0,'','[]',1,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('otherUserId','otherAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('testGroupId','testAccountId','testGroupName','api','["testPeerId"]',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('newGroupId','testAccountId','newGroupName','api','[]',0,'');
|
||||||
|
INSERT INTO setup_keys VALUES('testKeyId','testAccountId','testKey','testK****','existingKey','one-off','2021-08-19 20:46:20.000000000+00:00','2321-09-18 20:46:20.000000000+00:00','2021-08-19 20:46:20.000000000+00:000',0,0,NULL,'["testGroupId"]',1,0);
|
||||||
|
INSERT INTO peers VALUES('testPeerId','testAccountId','5rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYAg=','72546A29-6BC8-4311-BCFC-9CDBF33F1A48','"100.64.114.31"','f2a34f6a4731','linux','Linux','11','unknown','Debian GNU/Linux','','0.12.0','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'f2a34f6a4731','f2a34f6a4731','2023-03-02 09:21:02.189035775+01:00',0,0,0,'','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk',0,1,'2023-03-01 19:48:19.817799698+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
|
|
||||||
|
INSERT INTO policies VALUES('testPolicyId','testAccountId','testPolicy','test policy description',1,NULL);
|
||||||
|
INSERT INTO policy_rules VALUES('testRuleId','testPolicyId','testRule','test rule',1,'accept','all',1,'["testGroupId"]','["testGroupId"]',NULL,NULL,NULL,NULL,NULL,'');
|
||||||
23
management/server/http/testing/testdata/routes.sql
vendored
Normal file
23
management/server/http/testing/testdata/routes.sql
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
CREATE TABLE `accounts` (`id` text,`created_by` text,`created_at` datetime,`domain` text,`domain_category` text,`is_domain_primary_account` numeric,`network_identifier` text,`network_net` text,`network_dns` text,`network_serial` integer,`dns_settings_disabled_management_groups` text,`settings_peer_login_expiration_enabled` numeric,`settings_peer_login_expiration` integer,`settings_regular_users_view_blocked` numeric,`settings_groups_propagation_enabled` numeric,`settings_jwt_groups_enabled` numeric,`settings_jwt_groups_claim_name` text,`settings_jwt_allow_groups` text,`settings_extra_peer_approval_enabled` numeric,`settings_extra_integrated_validator_groups` text,PRIMARY KEY (`id`));
|
||||||
|
CREATE TABLE `users` (`id` text,`account_id` text,`role` text,`is_service_user` numeric,`non_deletable` numeric,`service_user_name` text,`auto_groups` text,`blocked` numeric,`last_login` datetime DEFAULT NULL,`created_at` datetime,`issued` text DEFAULT "api",`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_users_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `groups` (`id` text,`account_id` text,`name` text,`issued` text,`peers` text,`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_groups_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `setup_keys` (`id` text,`account_id` text,`key` text,`key_secret` text,`name` text,`type` text,`created_at` datetime,`expires_at` datetime,`updated_at` datetime,`revoked` numeric,`used_times` integer,`last_used` datetime DEFAULT NULL,`auto_groups` text,`usage_limit` integer,`ephemeral` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_setup_keys_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `peers` (`id` text,`account_id` text,`key` text,`setup_key` text,`ip` text,`meta_hostname` text,`meta_go_os` text,`meta_kernel` text,`meta_core` text,`meta_platform` text,`meta_os` text,`meta_os_version` text,`meta_wt_version` text,`meta_ui_version` text,`meta_kernel_version` text,`meta_network_addresses` text,`meta_system_serial_number` text,`meta_system_product_name` text,`meta_system_manufacturer` text,`meta_environment` text,`meta_files` text,`name` text,`dns_label` text,`peer_status_last_seen` datetime,`peer_status_connected` numeric,`peer_status_login_expired` numeric,`peer_status_requires_approval` numeric,`user_id` text,`ssh_key` text,`ssh_enabled` numeric,`login_expiration_enabled` numeric,`last_login` datetime,`created_at` datetime,`ephemeral` numeric,`location_connection_ip` text,`location_country_code` text,`location_city_name` text,`location_geo_name_id` integer,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_peers_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `routes` (`id` text,`account_id` text,`network` text,`domains` text,`keep_route` numeric,`net_id` text,`description` text,`peer` text,`peer_groups` text,`network_type` integer,`masquerade` numeric,`metric` integer,`enabled` numeric,`groups` text,`access_control_groups` text,`skip_auto_apply` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_routes_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
|
||||||
|
INSERT INTO accounts VALUES('testAccountId','','2024-10-02 16:01:38.000000000+00:00','test.com','private',1,'testNetworkIdentifier','{"IP":"100.64.0.0","Mask":"//8AAA=="}','',0,'[]',1,86400000000000,0,0,0,'',NULL,NULL,NULL);
|
||||||
|
INSERT INTO users VALUES('testUserId','testAccountId','user',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testAdminId','testAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testOwnerId','testAccountId','owner',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceUserId','testAccountId','user',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceAdminId','testAccountId','admin',1,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('blockedUserId','testAccountId','admin',0,0,'','[]',1,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('otherUserId','otherAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('testGroupId','testAccountId','testGroupName','api','["testPeerId"]',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('newGroupId','testAccountId','newGroupName','api','[]',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('peerGroupId','testAccountId','peerGroupName','api','["testPeerId"]',0,'');
|
||||||
|
INSERT INTO setup_keys VALUES('testKeyId','testAccountId','testKey','testK****','existingKey','one-off','2021-08-19 20:46:20.000000000+00:00','2321-09-18 20:46:20.000000000+00:00','2021-08-19 20:46:20.000000000+00:000',0,0,NULL,'["testGroupId"]',1,0);
|
||||||
|
INSERT INTO peers VALUES('testPeerId','testAccountId','5rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYAg=','72546A29-6BC8-4311-BCFC-9CDBF33F1A48','"100.64.114.31"','f2a34f6a4731','linux','Linux','11','unknown','Debian GNU/Linux','','0.12.0','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'f2a34f6a4731','f2a34f6a4731','2023-03-02 09:21:02.189035775+01:00',0,0,0,'','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk',0,1,'2023-03-01 19:48:19.817799698+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
|
|
||||||
|
INSERT INTO routes VALUES('testRouteId','testAccountId','"10.0.0.0/24"',NULL,0,'testNet','Test Network Route','testPeerId',NULL,1,1,100,1,'["testGroupId"]',NULL,0);
|
||||||
|
INSERT INTO routes VALUES('testDomainRouteId','testAccountId','"0.0.0.0/0"','["example.com"]',0,'testDomainNet','Test Domain Route','','["peerGroupId"]',3,1,200,1,'["testGroupId"]',NULL,0);
|
||||||
24
management/server/http/testing/testdata/users_integration.sql
vendored
Normal file
24
management/server/http/testing/testdata/users_integration.sql
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
CREATE TABLE `accounts` (`id` text,`created_by` text,`created_at` datetime,`domain` text,`domain_category` text,`is_domain_primary_account` numeric,`network_identifier` text,`network_net` text,`network_dns` text,`network_serial` integer,`dns_settings_disabled_management_groups` text,`settings_peer_login_expiration_enabled` numeric,`settings_peer_login_expiration` integer,`settings_regular_users_view_blocked` numeric,`settings_groups_propagation_enabled` numeric,`settings_jwt_groups_enabled` numeric,`settings_jwt_groups_claim_name` text,`settings_jwt_allow_groups` text,`settings_extra_peer_approval_enabled` numeric,`settings_extra_integrated_validator_groups` text,PRIMARY KEY (`id`));
|
||||||
|
CREATE TABLE `users` (`id` text,`account_id` text,`role` text,`is_service_user` numeric,`non_deletable` numeric,`service_user_name` text,`auto_groups` text,`blocked` numeric,`last_login` datetime DEFAULT NULL,`created_at` datetime,`issued` text DEFAULT "api",`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_users_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `groups` (`id` text,`account_id` text,`name` text,`issued` text,`peers` text,`integration_ref_id` integer,`integration_ref_integration_type` text,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_groups_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `setup_keys` (`id` text,`account_id` text,`key` text,`key_secret` text,`name` text,`type` text,`created_at` datetime,`expires_at` datetime,`updated_at` datetime,`revoked` numeric,`used_times` integer,`last_used` datetime DEFAULT NULL,`auto_groups` text,`usage_limit` integer,`ephemeral` numeric,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_setup_keys_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `peers` (`id` text,`account_id` text,`key` text,`setup_key` text,`ip` text,`meta_hostname` text,`meta_go_os` text,`meta_kernel` text,`meta_core` text,`meta_platform` text,`meta_os` text,`meta_os_version` text,`meta_wt_version` text,`meta_ui_version` text,`meta_kernel_version` text,`meta_network_addresses` text,`meta_system_serial_number` text,`meta_system_product_name` text,`meta_system_manufacturer` text,`meta_environment` text,`meta_files` text,`name` text,`dns_label` text,`peer_status_last_seen` datetime,`peer_status_connected` numeric,`peer_status_login_expired` numeric,`peer_status_requires_approval` numeric,`user_id` text,`ssh_key` text,`ssh_enabled` numeric,`login_expiration_enabled` numeric,`last_login` datetime,`created_at` datetime,`ephemeral` numeric,`location_connection_ip` text,`location_country_code` text,`location_city_name` text,`location_geo_name_id` integer,PRIMARY KEY (`id`),CONSTRAINT `fk_accounts_peers_g` FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`));
|
||||||
|
CREATE TABLE `personal_access_tokens` (`id` text,`user_id` text,`name` text,`hashed_token` text,`expiration_date` datetime,`created_by` text,`created_at` datetime,`last_used` datetime DEFAULT NULL,PRIMARY KEY (`id`),CONSTRAINT `fk_users_pa_ts_g` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`));
|
||||||
|
CREATE INDEX `idx_personal_access_tokens_user_id` ON `personal_access_tokens`(`user_id`);
|
||||||
|
|
||||||
|
INSERT INTO accounts VALUES('testAccountId','','2024-10-02 16:01:38.000000000+00:00','test.com','private',1,'testNetworkIdentifier','{"IP":"100.64.0.0","Mask":"//8AAA=="}','',0,'[]',1,86400000000000,0,0,0,'',NULL,NULL,NULL);
|
||||||
|
INSERT INTO users VALUES('testUserId','testAccountId','user',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testAdminId','testAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testOwnerId','testAccountId','owner',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceUserId','testAccountId','user',1,0,'testServiceUser','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('testServiceAdminId','testAccountId','admin',1,0,'testServiceAdmin','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('blockedUserId','testAccountId','admin',0,0,'','[]',1,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('otherUserId','otherAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO users VALUES('deletableServiceUserId','testAccountId','user',1,0,'deletableServiceUser','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('testGroupId','testAccountId','testGroupName','api','["testPeerId"]',0,'');
|
||||||
|
INSERT INTO "groups" VALUES('newGroupId','testAccountId','newGroupName','api','[]',0,'');
|
||||||
|
INSERT INTO setup_keys VALUES('testKeyId','testAccountId','testKey','testK****','existingKey','one-off','2021-08-19 20:46:20.000000000+00:00','2321-09-18 20:46:20.000000000+00:00','2021-08-19 20:46:20.000000000+00:000',0,0,NULL,'["testGroupId"]',1,0);
|
||||||
|
INSERT INTO peers VALUES('testPeerId','testAccountId','5rvhvriKJZ3S9oxYToVj5TzDM9u9y8cxg7htIMWlYAg=','72546A29-6BC8-4311-BCFC-9CDBF33F1A48','"100.64.114.31"','f2a34f6a4731','linux','Linux','11','unknown','Debian GNU/Linux','','0.12.0','','',NULL,'','','','{"Cloud":"","Platform":""}',NULL,'f2a34f6a4731','f2a34f6a4731','2023-03-02 09:21:02.189035775+01:00',0,0,0,'','ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILzUUSYG/LGnV8zarb2SGN+tib/PZ+M7cL4WtTzUrTpk',0,1,'2023-03-01 19:48:19.817799698+01:00','2024-10-02 17:00:32.527947+02:00',0,'""','','',0);
|
||||||
|
|
||||||
|
INSERT INTO personal_access_tokens VALUES('testTokenId','testUserId','testToken','hashedTokenValue123','2325-10-02 16:01:38.000000000+00:00','testUserId','2024-10-02 16:01:38.000000000+00:00',NULL);
|
||||||
|
INSERT INTO personal_access_tokens VALUES('serviceTokenId','testServiceUserId','serviceToken','hashedServiceTokenValue123','2325-10-02 16:01:38.000000000+00:00','testAdminId','2024-10-02 16:01:38.000000000+00:00',NULL);
|
||||||
@@ -128,14 +128,14 @@ func BuildApiBlackBoxWithDBState(t testing_tools.TB, sqlFile string, expectedPee
|
|||||||
GetPATInfoFunc: authManager.GetPATInfo,
|
GetPATInfoFunc: authManager.GetPATInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
networksManagerMock := networks.NewManagerMock()
|
groupsManager := groups.NewManager(store, permissionsManager, am)
|
||||||
resourcesManagerMock := resources.NewManagerMock()
|
routersManager := routers.NewManager(store, permissionsManager, am)
|
||||||
routersManagerMock := routers.NewManagerMock()
|
resourcesManager := resources.NewManager(store, permissionsManager, groupsManager, am, serviceManager)
|
||||||
groupsManagerMock := groups.NewManagerMock()
|
networksManager := networks.NewManager(store, permissionsManager, resourcesManager, routersManager, am)
|
||||||
customZonesManager := zonesManager.NewManager(store, am, permissionsManager, "")
|
customZonesManager := zonesManager.NewManager(store, am, permissionsManager, "")
|
||||||
zoneRecordsManager := recordsManager.NewManager(store, am, permissionsManager)
|
zoneRecordsManager := recordsManager.NewManager(store, am, permissionsManager)
|
||||||
|
|
||||||
apiHandler, err := http2.NewAPIHandler(context.Background(), am, networksManagerMock, resourcesManagerMock, routersManagerMock, groupsManagerMock, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManager, peersManager, settingsManager, customZonesManager, zoneRecordsManager, networkMapController, nil, serviceManager, nil, nil, nil, nil)
|
apiHandler, err := http2.NewAPIHandler(context.Background(), am, networksManager, resourcesManager, routersManager, groupsManager, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManager, peersManager, settingsManager, customZonesManager, zoneRecordsManager, networkMapController, nil, serviceManager, nil, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create API handler: %v", err)
|
t.Fatalf("Failed to create API handler: %v", err)
|
||||||
}
|
}
|
||||||
@@ -167,6 +167,112 @@ func peerShouldReceiveUpdate(t testing_tools.TB, updateMessage <-chan *network_m
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PeerShouldReceiveAnyUpdate waits for a peer update message and returns it.
|
||||||
|
// Fails the test if no update is received within timeout.
|
||||||
|
func PeerShouldReceiveAnyUpdate(t testing_tools.TB, updateMessage <-chan *network_map.UpdateMessage) *network_map.UpdateMessage {
|
||||||
|
t.Helper()
|
||||||
|
select {
|
||||||
|
case msg := <-updateMessage:
|
||||||
|
if msg == nil {
|
||||||
|
t.Errorf("Received nil update message, expected valid message")
|
||||||
|
}
|
||||||
|
return msg
|
||||||
|
case <-time.After(500 * time.Millisecond):
|
||||||
|
t.Errorf("Timed out waiting for update message")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PeerShouldNotReceiveAnyUpdate verifies no peer update message is received.
|
||||||
|
func PeerShouldNotReceiveAnyUpdate(t testing_tools.TB, updateMessage <-chan *network_map.UpdateMessage) {
|
||||||
|
t.Helper()
|
||||||
|
peerShouldNotReceiveUpdate(t, updateMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildApiBlackBoxWithDBStateAndPeerChannel creates the API handler and returns
|
||||||
|
// the peer update channel directly so tests can verify updates inline.
|
||||||
|
func BuildApiBlackBoxWithDBStateAndPeerChannel(t testing_tools.TB, sqlFile string) (http.Handler, account.Manager, <-chan *network_map.UpdateMessage) {
|
||||||
|
store, cleanup, err := store.NewTestStoreFromSQL(context.Background(), sqlFile, t.TempDir())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create test store: %v", err)
|
||||||
|
}
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
|
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create metrics: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
peersUpdateManager := update_channel.NewPeersUpdateManager(nil)
|
||||||
|
updMsg := peersUpdateManager.CreateChannel(context.Background(), testing_tools.TestPeerId)
|
||||||
|
|
||||||
|
geoMock := &geolocation.Mock{}
|
||||||
|
validatorMock := server.MockIntegratedValidator{}
|
||||||
|
proxyController := integrations.NewController(store)
|
||||||
|
userManager := users.NewManager(store)
|
||||||
|
permissionsManager := permissions.NewManager(store)
|
||||||
|
settingsManager := settings.NewManager(store, userManager, integrations.NewManager(&activity.InMemoryEventStore{}), permissionsManager, settings.IdpConfig{})
|
||||||
|
peersManager := peers.NewManager(store, permissionsManager)
|
||||||
|
|
||||||
|
jobManager := job.NewJobManager(nil, store, peersManager)
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
requestBuffer := server.NewAccountRequestBuffer(ctx, store)
|
||||||
|
networkMapController := controller.NewController(ctx, store, metrics, peersUpdateManager, requestBuffer, server.MockIntegratedValidator{}, settingsManager, "", port_forwarding.NewControllerMock(), ephemeral_manager.NewEphemeralManager(store, peersManager), &config.Config{})
|
||||||
|
am, err := server.BuildManager(ctx, nil, store, networkMapController, jobManager, nil, "", &activity.InMemoryEventStore{}, geoMock, false, validatorMock, metrics, proxyController, settingsManager, permissionsManager, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create manager: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
accessLogsManager := accesslogsmanager.NewManager(store, permissionsManager, nil)
|
||||||
|
proxyTokenStore, err := nbgrpc.NewOneTimeTokenStore(ctx, 5*time.Minute, 10*time.Minute, 100)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create proxy token store: %v", err)
|
||||||
|
}
|
||||||
|
pkceverifierStore, err := nbgrpc.NewPKCEVerifierStore(ctx, 10*time.Minute, 10*time.Minute, 100)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create PKCE verifier store: %v", err)
|
||||||
|
}
|
||||||
|
noopMeter := noop.NewMeterProvider().Meter("")
|
||||||
|
proxyMgr, err := proxymanager.NewManager(store, noopMeter)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create proxy manager: %v", err)
|
||||||
|
}
|
||||||
|
proxyServiceServer := nbgrpc.NewProxyServiceServer(accessLogsManager, proxyTokenStore, pkceverifierStore, nbgrpc.ProxyOIDCConfig{}, peersManager, userManager, proxyMgr)
|
||||||
|
domainManager := manager.NewManager(store, proxyMgr, permissionsManager, am)
|
||||||
|
serviceProxyController, err := proxymanager.NewGRPCController(proxyServiceServer, noopMeter)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create proxy controller: %v", err)
|
||||||
|
}
|
||||||
|
domainManager.SetClusterCapabilities(serviceProxyController)
|
||||||
|
serviceManager := reverseproxymanager.NewManager(store, am, permissionsManager, serviceProxyController, domainManager)
|
||||||
|
proxyServiceServer.SetServiceManager(serviceManager)
|
||||||
|
am.SetServiceManager(serviceManager)
|
||||||
|
|
||||||
|
// @note this is required so that PAT's validate from store, but JWT's are mocked
|
||||||
|
authManager := serverauth.NewManager(store, "", "", "", "", []string{}, false)
|
||||||
|
authManagerMock := &serverauth.MockManager{
|
||||||
|
ValidateAndParseTokenFunc: mockValidateAndParseToken,
|
||||||
|
EnsureUserAccessByJWTGroupsFunc: authManager.EnsureUserAccessByJWTGroups,
|
||||||
|
MarkPATUsedFunc: authManager.MarkPATUsed,
|
||||||
|
GetPATInfoFunc: authManager.GetPATInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
groupsManager := groups.NewManager(store, permissionsManager, am)
|
||||||
|
routersManager := routers.NewManager(store, permissionsManager, am)
|
||||||
|
resourcesManager := resources.NewManager(store, permissionsManager, groupsManager, am, serviceManager)
|
||||||
|
networksManager := networks.NewManager(store, permissionsManager, resourcesManager, routersManager, am)
|
||||||
|
customZonesManager := zonesManager.NewManager(store, am, permissionsManager, "")
|
||||||
|
zoneRecordsManager := recordsManager.NewManager(store, am, permissionsManager)
|
||||||
|
|
||||||
|
apiHandler, err := http2.NewAPIHandler(context.Background(), am, networksManager, resourcesManager, routersManager, groupsManager, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManager, peersManager, settingsManager, customZonesManager, zoneRecordsManager, networkMapController, nil, serviceManager, nil, nil, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create API handler: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiHandler, am, updMsg
|
||||||
|
}
|
||||||
|
|
||||||
func mockValidateAndParseToken(_ context.Context, token string) (auth.UserAuth, *jwt.Token, error) {
|
func mockValidateAndParseToken(_ context.Context, token string) (auth.UserAuth, *jwt.Token, error) {
|
||||||
userAuth := auth.UserAuth{}
|
userAuth := auth.UserAuth{}
|
||||||
|
|
||||||
|
|||||||
222
management/server/http/testing/testing_tools/db_verify.go
Normal file
222
management/server/http/testing/testing_tools/db_verify.go
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
package testing_tools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
|
resourceTypes "github.com/netbirdio/netbird/management/server/networks/resources/types"
|
||||||
|
routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types"
|
||||||
|
networkTypes "github.com/netbirdio/netbird/management/server/networks/types"
|
||||||
|
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||||
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
|
"github.com/netbirdio/netbird/route"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetDB extracts the *gorm.DB from a store.Store (must be *SqlStore).
|
||||||
|
func GetDB(t *testing.T, s store.Store) *gorm.DB {
|
||||||
|
t.Helper()
|
||||||
|
sqlStore, ok := s.(*store.SqlStore)
|
||||||
|
require.True(t, ok, "Store is not a *SqlStore, cannot get gorm.DB")
|
||||||
|
return sqlStore.GetDB()
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyGroupInDB reads a group directly from the DB and returns it.
|
||||||
|
func VerifyGroupInDB(t *testing.T, db *gorm.DB, groupID string) *types.Group {
|
||||||
|
t.Helper()
|
||||||
|
var group types.Group
|
||||||
|
err := db.Where("id = ? AND account_id = ?", groupID, TestAccountId).First(&group).Error
|
||||||
|
require.NoError(t, err, "Expected group %s to exist in DB", groupID)
|
||||||
|
return &group
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyGroupNotInDB verifies that a group does not exist in the DB.
|
||||||
|
func VerifyGroupNotInDB(t *testing.T, db *gorm.DB, groupID string) {
|
||||||
|
t.Helper()
|
||||||
|
var count int64
|
||||||
|
db.Model(&types.Group{}).Where("id = ? AND account_id = ?", groupID, TestAccountId).Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "Expected group %s to NOT exist in DB", groupID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyPolicyInDB reads a policy directly from the DB and returns it.
|
||||||
|
func VerifyPolicyInDB(t *testing.T, db *gorm.DB, policyID string) *types.Policy {
|
||||||
|
t.Helper()
|
||||||
|
var policy types.Policy
|
||||||
|
err := db.Preload("Rules").Where("id = ? AND account_id = ?", policyID, TestAccountId).First(&policy).Error
|
||||||
|
require.NoError(t, err, "Expected policy %s to exist in DB", policyID)
|
||||||
|
return &policy
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyPolicyNotInDB verifies that a policy does not exist in the DB.
|
||||||
|
func VerifyPolicyNotInDB(t *testing.T, db *gorm.DB, policyID string) {
|
||||||
|
t.Helper()
|
||||||
|
var count int64
|
||||||
|
db.Model(&types.Policy{}).Where("id = ? AND account_id = ?", policyID, TestAccountId).Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "Expected policy %s to NOT exist in DB", policyID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyRouteInDB reads a route directly from the DB and returns it.
|
||||||
|
func VerifyRouteInDB(t *testing.T, db *gorm.DB, routeID route.ID) *route.Route {
|
||||||
|
t.Helper()
|
||||||
|
var r route.Route
|
||||||
|
err := db.Where("id = ? AND account_id = ?", routeID, TestAccountId).First(&r).Error
|
||||||
|
require.NoError(t, err, "Expected route %s to exist in DB", routeID)
|
||||||
|
return &r
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyRouteNotInDB verifies that a route does not exist in the DB.
|
||||||
|
func VerifyRouteNotInDB(t *testing.T, db *gorm.DB, routeID route.ID) {
|
||||||
|
t.Helper()
|
||||||
|
var count int64
|
||||||
|
db.Model(&route.Route{}).Where("id = ? AND account_id = ?", routeID, TestAccountId).Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "Expected route %s to NOT exist in DB", routeID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyNSGroupInDB reads a nameserver group directly from the DB and returns it.
|
||||||
|
func VerifyNSGroupInDB(t *testing.T, db *gorm.DB, nsGroupID string) *nbdns.NameServerGroup {
|
||||||
|
t.Helper()
|
||||||
|
var nsGroup nbdns.NameServerGroup
|
||||||
|
err := db.Where("id = ? AND account_id = ?", nsGroupID, TestAccountId).First(&nsGroup).Error
|
||||||
|
require.NoError(t, err, "Expected NS group %s to exist in DB", nsGroupID)
|
||||||
|
return &nsGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyNSGroupNotInDB verifies that a nameserver group does not exist in the DB.
|
||||||
|
func VerifyNSGroupNotInDB(t *testing.T, db *gorm.DB, nsGroupID string) {
|
||||||
|
t.Helper()
|
||||||
|
var count int64
|
||||||
|
db.Model(&nbdns.NameServerGroup{}).Where("id = ? AND account_id = ?", nsGroupID, TestAccountId).Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "Expected NS group %s to NOT exist in DB", nsGroupID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyPeerInDB reads a peer directly from the DB and returns it.
|
||||||
|
func VerifyPeerInDB(t *testing.T, db *gorm.DB, peerID string) *nbpeer.Peer {
|
||||||
|
t.Helper()
|
||||||
|
var peer nbpeer.Peer
|
||||||
|
err := db.Where("id = ? AND account_id = ?", peerID, TestAccountId).First(&peer).Error
|
||||||
|
require.NoError(t, err, "Expected peer %s to exist in DB", peerID)
|
||||||
|
return &peer
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyPeerNotInDB verifies that a peer does not exist in the DB.
|
||||||
|
func VerifyPeerNotInDB(t *testing.T, db *gorm.DB, peerID string) {
|
||||||
|
t.Helper()
|
||||||
|
var count int64
|
||||||
|
db.Model(&nbpeer.Peer{}).Where("id = ? AND account_id = ?", peerID, TestAccountId).Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "Expected peer %s to NOT exist in DB", peerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifySetupKeyInDB reads a setup key directly from the DB and returns it.
|
||||||
|
func VerifySetupKeyInDB(t *testing.T, db *gorm.DB, keyID string) *types.SetupKey {
|
||||||
|
t.Helper()
|
||||||
|
var key types.SetupKey
|
||||||
|
err := db.Where("id = ? AND account_id = ?", keyID, TestAccountId).First(&key).Error
|
||||||
|
require.NoError(t, err, "Expected setup key %s to exist in DB", keyID)
|
||||||
|
return &key
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifySetupKeyNotInDB verifies that a setup key does not exist in the DB.
|
||||||
|
func VerifySetupKeyNotInDB(t *testing.T, db *gorm.DB, keyID string) {
|
||||||
|
t.Helper()
|
||||||
|
var count int64
|
||||||
|
db.Model(&types.SetupKey{}).Where("id = ? AND account_id = ?", keyID, TestAccountId).Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "Expected setup key %s to NOT exist in DB", keyID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyUserInDB reads a user directly from the DB and returns it.
|
||||||
|
func VerifyUserInDB(t *testing.T, db *gorm.DB, userID string) *types.User {
|
||||||
|
t.Helper()
|
||||||
|
var user types.User
|
||||||
|
err := db.Where("id = ? AND account_id = ?", userID, TestAccountId).First(&user).Error
|
||||||
|
require.NoError(t, err, "Expected user %s to exist in DB", userID)
|
||||||
|
return &user
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyUserNotInDB verifies that a user does not exist in the DB.
|
||||||
|
func VerifyUserNotInDB(t *testing.T, db *gorm.DB, userID string) {
|
||||||
|
t.Helper()
|
||||||
|
var count int64
|
||||||
|
db.Model(&types.User{}).Where("id = ? AND account_id = ?", userID, TestAccountId).Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "Expected user %s to NOT exist in DB", userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyPATInDB reads a PAT directly from the DB and returns it.
|
||||||
|
func VerifyPATInDB(t *testing.T, db *gorm.DB, tokenID string) *types.PersonalAccessToken {
|
||||||
|
t.Helper()
|
||||||
|
var pat types.PersonalAccessToken
|
||||||
|
err := db.Where("id = ?", tokenID).First(&pat).Error
|
||||||
|
require.NoError(t, err, "Expected PAT %s to exist in DB", tokenID)
|
||||||
|
return &pat
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyPATNotInDB verifies that a PAT does not exist in the DB.
|
||||||
|
func VerifyPATNotInDB(t *testing.T, db *gorm.DB, tokenID string) {
|
||||||
|
t.Helper()
|
||||||
|
var count int64
|
||||||
|
db.Model(&types.PersonalAccessToken{}).Where("id = ?", tokenID).Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "Expected PAT %s to NOT exist in DB", tokenID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyAccountSettings reads the account and returns its settings from the DB.
|
||||||
|
func VerifyAccountSettings(t *testing.T, db *gorm.DB) *types.Account {
|
||||||
|
t.Helper()
|
||||||
|
var account types.Account
|
||||||
|
err := db.Where("id = ?", TestAccountId).First(&account).Error
|
||||||
|
require.NoError(t, err, "Expected account %s to exist in DB", TestAccountId)
|
||||||
|
return &account
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyNetworkInDB reads a network directly from the store and returns it.
|
||||||
|
func VerifyNetworkInDB(t *testing.T, db *gorm.DB, networkID string) *networkTypes.Network {
|
||||||
|
t.Helper()
|
||||||
|
var network networkTypes.Network
|
||||||
|
err := db.Where("id = ? AND account_id = ?", networkID, TestAccountId).First(&network).Error
|
||||||
|
require.NoError(t, err, "Expected network %s to exist in DB", networkID)
|
||||||
|
return &network
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyNetworkNotInDB verifies that a network does not exist in the DB.
|
||||||
|
func VerifyNetworkNotInDB(t *testing.T, db *gorm.DB, networkID string) {
|
||||||
|
t.Helper()
|
||||||
|
var count int64
|
||||||
|
db.Model(&networkTypes.Network{}).Where("id = ? AND account_id = ?", networkID, TestAccountId).Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "Expected network %s to NOT exist in DB", networkID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyNetworkResourceInDB reads a network resource directly from the DB and returns it.
|
||||||
|
func VerifyNetworkResourceInDB(t *testing.T, db *gorm.DB, resourceID string) *resourceTypes.NetworkResource {
|
||||||
|
t.Helper()
|
||||||
|
var resource resourceTypes.NetworkResource
|
||||||
|
err := db.Where("id = ? AND account_id = ?", resourceID, TestAccountId).First(&resource).Error
|
||||||
|
require.NoError(t, err, "Expected network resource %s to exist in DB", resourceID)
|
||||||
|
return &resource
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyNetworkResourceNotInDB verifies that a network resource does not exist in the DB.
|
||||||
|
func VerifyNetworkResourceNotInDB(t *testing.T, db *gorm.DB, resourceID string) {
|
||||||
|
t.Helper()
|
||||||
|
var count int64
|
||||||
|
db.Model(&resourceTypes.NetworkResource{}).Where("id = ? AND account_id = ?", resourceID, TestAccountId).Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "Expected network resource %s to NOT exist in DB", resourceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyNetworkRouterInDB reads a network router directly from the DB and returns it.
|
||||||
|
func VerifyNetworkRouterInDB(t *testing.T, db *gorm.DB, routerID string) *routerTypes.NetworkRouter {
|
||||||
|
t.Helper()
|
||||||
|
var router routerTypes.NetworkRouter
|
||||||
|
err := db.Where("id = ? AND account_id = ?", routerID, TestAccountId).First(&router).Error
|
||||||
|
require.NoError(t, err, "Expected network router %s to exist in DB", routerID)
|
||||||
|
return &router
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyNetworkRouterNotInDB verifies that a network router does not exist in the DB.
|
||||||
|
func VerifyNetworkRouterNotInDB(t *testing.T, db *gorm.DB, routerID string) {
|
||||||
|
t.Helper()
|
||||||
|
var count int64
|
||||||
|
db.Model(&routerTypes.NetworkRouter{}).Where("id = ? AND account_id = ?", routerID, TestAccountId).Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "Expected network router %s to NOT exist in DB", routerID)
|
||||||
|
}
|
||||||
@@ -5494,3 +5494,61 @@ func (s *SqlStore) CleanupStaleProxies(ctx context.Context, inactivityDuration t
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRoutingPeerNetworks returns the distinct network names where the peer is assigned as a routing peer
|
||||||
|
// in an enabled network router, either directly or via peer groups.
|
||||||
|
func (s *SqlStore) GetRoutingPeerNetworks(_ context.Context, accountID, peerID string) ([]string, error) {
|
||||||
|
var routers []*routerTypes.NetworkRouter
|
||||||
|
if err := s.db.Select("peer, peer_groups, network_id").Where("account_id = ? AND enabled = true", accountID).Find(&routers).Error; err != nil {
|
||||||
|
return nil, status.Errorf(status.Internal, "failed to get enabled routers: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(routers) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var groupPeers []types.GroupPeer
|
||||||
|
if err := s.db.Select("group_id").Where("account_id = ? AND peer_id = ?", accountID, peerID).Find(&groupPeers).Error; err != nil {
|
||||||
|
return nil, status.Errorf(status.Internal, "failed to get peer group memberships: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
groupSet := make(map[string]struct{}, len(groupPeers))
|
||||||
|
for _, gp := range groupPeers {
|
||||||
|
groupSet[gp.GroupID] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
networkIDs := make(map[string]struct{})
|
||||||
|
for _, r := range routers {
|
||||||
|
if r.Peer == peerID {
|
||||||
|
networkIDs[r.NetworkID] = struct{}{}
|
||||||
|
} else if r.Peer == "" {
|
||||||
|
for _, pg := range r.PeerGroups {
|
||||||
|
if _, ok := groupSet[pg]; ok {
|
||||||
|
networkIDs[r.NetworkID] = struct{}{}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(networkIDs) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ids := make([]string, 0, len(networkIDs))
|
||||||
|
for id := range networkIDs {
|
||||||
|
ids = append(ids, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
var networks []*networkTypes.Network
|
||||||
|
if err := s.db.Select("name").Where("account_id = ? AND id IN ?", accountID, ids).Find(&networks).Error; err != nil {
|
||||||
|
return nil, status.Errorf(status.Internal, "failed to get networks: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
names := make([]string, 0, len(networks))
|
||||||
|
for _, n := range networks {
|
||||||
|
names = append(names, n.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return names, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -290,6 +290,8 @@ type Store interface {
|
|||||||
CleanupStaleProxies(ctx context.Context, inactivityDuration time.Duration) error
|
CleanupStaleProxies(ctx context.Context, inactivityDuration time.Duration) error
|
||||||
|
|
||||||
GetCustomDomainsCounts(ctx context.Context) (total int64, validated int64, err error)
|
GetCustomDomainsCounts(ctx context.Context) (total int64, validated int64, err error)
|
||||||
|
|
||||||
|
GetRoutingPeerNetworks(ctx context.Context, accountID, peerID string) ([]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -2333,6 +2333,21 @@ func (mr *MockStoreMockRecorder) IncrementSetupKeyUsage(ctx, setupKeyID interfac
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IncrementSetupKeyUsage", reflect.TypeOf((*MockStore)(nil).IncrementSetupKeyUsage), ctx, setupKeyID)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IncrementSetupKeyUsage", reflect.TypeOf((*MockStore)(nil).IncrementSetupKeyUsage), ctx, setupKeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRoutingPeerNetworks mocks base method.
|
||||||
|
func (m *MockStore) GetRoutingPeerNetworks(ctx context.Context, accountID, peerID string) ([]string, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "GetRoutingPeerNetworks", ctx, accountID, peerID)
|
||||||
|
ret0, _ := ret[0].([]string)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRoutingPeerNetworks indicates an expected call of GetRoutingPeerNetworks.
|
||||||
|
func (mr *MockStoreMockRecorder) GetRoutingPeerNetworks(ctx, accountID, peerID interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRoutingPeerNetworks", reflect.TypeOf((*MockStore)(nil).GetRoutingPeerNetworks), ctx, accountID, peerID)
|
||||||
|
}
|
||||||
|
|
||||||
// IsPrimaryAccount mocks base method.
|
// IsPrimaryAccount mocks base method.
|
||||||
func (m *MockStore) IsPrimaryAccount(ctx context.Context, accountID string) (bool, string, error) {
|
func (m *MockStore) IsPrimaryAccount(ctx context.Context, accountID string) (bool, string, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|||||||
@@ -89,6 +89,10 @@ tags:
|
|||||||
- name: Event Streaming Integrations
|
- name: Event Streaming Integrations
|
||||||
description: Manage event streaming integrations.
|
description: Manage event streaming integrations.
|
||||||
x-cloud-only: true
|
x-cloud-only: true
|
||||||
|
- name: Notifications
|
||||||
|
description: Manage notification channels for account event alerts.
|
||||||
|
x-cloud-only: true
|
||||||
|
|
||||||
|
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
@@ -2995,6 +2999,11 @@ components:
|
|||||||
type: boolean
|
type: boolean
|
||||||
description: Whether the service is enabled
|
description: Whether the service is enabled
|
||||||
example: true
|
example: true
|
||||||
|
terminated:
|
||||||
|
type: boolean
|
||||||
|
description: Whether the service has been terminated. Terminated services cannot be updated. Services that violate the Terms of Service will be terminated.
|
||||||
|
readOnly: true
|
||||||
|
example: false
|
||||||
pass_host_header:
|
pass_host_header:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: When true, the original client Host header is passed through to the backend instead of being rewritten to the backend's address
|
description: When true, the original client Host header is passed through to the backend instead of being rewritten to the backend's address
|
||||||
@@ -3654,6 +3663,156 @@ components:
|
|||||||
example: "https://invoice.stripe.com/i/acct_1M2DaBKina4I2KUb/test_YWNjdF8xTTJEdVBLaW5hM0kyS1ViLF1SeFpQdEJZd3lUOGNEajNqeWdrdXY2RFM4aHcyCnpsLDEzMjg3GTgyNQ02000JoIHc1X?s=db"
|
example: "https://invoice.stripe.com/i/acct_1M2DaBKina4I2KUb/test_YWNjdF8xTTJEdVBLaW5hM0kyS1ViLF1SeFpQdEJZd3lUOGNEajNqeWdrdXY2RFM4aHcyCnpsLDEzMjg3GTgyNQ02000JoIHc1X?s=db"
|
||||||
required:
|
required:
|
||||||
- url
|
- url
|
||||||
|
MSPStatusResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
description: Tenant account ID (present only for tenants)
|
||||||
|
example: ch8i4ug6lnn4g9hqv7m0
|
||||||
|
parent:
|
||||||
|
type: string
|
||||||
|
description: Parent MSP account ID (present only for tenants)
|
||||||
|
example: ch8i4ug6lnn4g9hqv7m1
|
||||||
|
activated_at:
|
||||||
|
type: string
|
||||||
|
description: MSP or Tenant activation timestamp in RFC3339 format
|
||||||
|
example: "2024-01-01T00:00:00Z"
|
||||||
|
invited_at:
|
||||||
|
type: string
|
||||||
|
description: Tenant invitation timestamp in RFC3339 format (present only for tenants)
|
||||||
|
example: "2024-01-01T00:00:00Z"
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
description: Tenant status (present only for tenants)
|
||||||
|
enum: ["existing", "invited", "pending", "active"]
|
||||||
|
example: active
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: MSP name (present only for MSP accounts)
|
||||||
|
example: "My MSP"
|
||||||
|
domain:
|
||||||
|
type: string
|
||||||
|
description: MSP domain (present only for MSP accounts)
|
||||||
|
example: "msp.com"
|
||||||
|
has_reseller:
|
||||||
|
type: boolean
|
||||||
|
description: Whether the MSP has a reseller (present only for MSP accounts)
|
||||||
|
default: false
|
||||||
|
example: false
|
||||||
|
is_reseller:
|
||||||
|
type: boolean
|
||||||
|
description: Whether the account is a reseller
|
||||||
|
default: false
|
||||||
|
example: false
|
||||||
|
parent_name:
|
||||||
|
type: string
|
||||||
|
description: Parent MSP name (present only for tenants)
|
||||||
|
example: "My MSP"
|
||||||
|
parent_domain:
|
||||||
|
type: string
|
||||||
|
description: Parent MSP domain (present only for tenants)
|
||||||
|
example: "msp.com"
|
||||||
|
parent_owner_name:
|
||||||
|
type: string
|
||||||
|
description: Parent MSP owner name
|
||||||
|
example: "John Doe"
|
||||||
|
parent_owner_email:
|
||||||
|
type: string
|
||||||
|
description: Parent MSP owner email
|
||||||
|
example: "john@msp.com"
|
||||||
|
ResellerStatusResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
activated_at:
|
||||||
|
type: string
|
||||||
|
description: Reseller activation timestamp in RFC3339 format
|
||||||
|
example: "2024-01-01T00:00:00Z"
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: Reseller name
|
||||||
|
example: "My Reseller"
|
||||||
|
domain:
|
||||||
|
type: string
|
||||||
|
description: Reseller domain
|
||||||
|
example: "reseller.com"
|
||||||
|
parent_owner_name:
|
||||||
|
type: string
|
||||||
|
description: Reseller owner name
|
||||||
|
example: "John Doe"
|
||||||
|
parent_owner_email:
|
||||||
|
type: string
|
||||||
|
description: Reseller owner email
|
||||||
|
example: "john@reseller.com"
|
||||||
|
ResellerMSPResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
description: The MSP account ID
|
||||||
|
example: ch8i4ug6lnn4g9hqv7m0
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The MSP name
|
||||||
|
example: "Partner MSP"
|
||||||
|
domain:
|
||||||
|
type: string
|
||||||
|
description: The MSP domain
|
||||||
|
example: "partner-msp.com"
|
||||||
|
has_reseller:
|
||||||
|
type: boolean
|
||||||
|
description: Whether the MSP is managed by a reseller
|
||||||
|
example: true
|
||||||
|
reseller_customer_id:
|
||||||
|
type: string
|
||||||
|
description: Reseller's internal customer reference for this MSP
|
||||||
|
example: "CUST-12345"
|
||||||
|
activated_at:
|
||||||
|
type: string
|
||||||
|
description: MSP activation timestamp in RFC3339 format
|
||||||
|
example: "2024-01-01T00:00:00Z"
|
||||||
|
invited_at:
|
||||||
|
type: string
|
||||||
|
description: MSP invitation timestamp in RFC3339 format
|
||||||
|
example: "2024-01-01T00:00:00Z"
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- name
|
||||||
|
- domain
|
||||||
|
- has_reseller
|
||||||
|
GetResellerMSPsResponse:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/ResellerMSPResponse"
|
||||||
|
CreateResellerMSPRequest:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The name for the MSP
|
||||||
|
example: "New Partner MSP"
|
||||||
|
domain:
|
||||||
|
type: string
|
||||||
|
description: The domain for the MSP
|
||||||
|
example: "new-partner.com"
|
||||||
|
priceID:
|
||||||
|
type: string
|
||||||
|
description: Stripe price ID to set up managed subscription for the MSP
|
||||||
|
example: "price_1234"
|
||||||
|
reseller_customer_id:
|
||||||
|
type: string
|
||||||
|
description: Reseller's internal customer reference for this MSP
|
||||||
|
example: "CUST-12345"
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- domain
|
||||||
|
UpdateResellerMSPRequest:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
reseller_customer_id:
|
||||||
|
type: string
|
||||||
|
description: Reseller's internal customer reference for this MSP
|
||||||
|
example: "CUST-12345"
|
||||||
CreateTenantRequest:
|
CreateTenantRequest:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -4385,6 +4544,123 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
description: The newly generated SCIM API token
|
description: The newly generated SCIM API token
|
||||||
example: "nbs_F3f0d..."
|
example: "nbs_F3f0d..."
|
||||||
|
NotificationChannelType:
|
||||||
|
type: string
|
||||||
|
description: The type of notification channel.
|
||||||
|
enum:
|
||||||
|
- email
|
||||||
|
- webhook
|
||||||
|
example: "email"
|
||||||
|
NotificationEventType:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
An activity event type code. See `GET /api/integrations/notifications/types` for the full list
|
||||||
|
of supported event types and their human-readable descriptions.
|
||||||
|
example: "user.join"
|
||||||
|
EmailTarget:
|
||||||
|
type: object
|
||||||
|
description: Target configuration for email notification channels.
|
||||||
|
properties:
|
||||||
|
emails:
|
||||||
|
type: array
|
||||||
|
description: List of email addresses to send notifications to.
|
||||||
|
minItems: 1
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
example: [ "admin@example.com", "ops@example.com" ]
|
||||||
|
required:
|
||||||
|
- emails
|
||||||
|
WebhookTarget:
|
||||||
|
type: object
|
||||||
|
description: Target configuration for webhook notification channels.
|
||||||
|
properties:
|
||||||
|
url:
|
||||||
|
type: string
|
||||||
|
format: uri
|
||||||
|
description: The webhook endpoint URL to send notifications to.
|
||||||
|
example: "https://hooks.example.com/netbird"
|
||||||
|
headers:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: |
|
||||||
|
Custom HTTP headers sent with each webhook request.
|
||||||
|
Values are write-only; in GET responses all values are masked.
|
||||||
|
example:
|
||||||
|
Authorization: "Bearer token"
|
||||||
|
X-Webhook-Secret: "secret"
|
||||||
|
required:
|
||||||
|
- url
|
||||||
|
NotificationChannelRequest:
|
||||||
|
type: object
|
||||||
|
description: Request body for creating or updating a notification channel.
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/NotificationChannelType'
|
||||||
|
target:
|
||||||
|
description: |
|
||||||
|
Channel-specific target configuration. The shape depends on the `type` field:
|
||||||
|
- `email`: requires an `EmailTarget` object
|
||||||
|
- `webhook`: requires a `WebhookTarget` object
|
||||||
|
oneOf:
|
||||||
|
- $ref: '#/components/schemas/EmailTarget'
|
||||||
|
- $ref: '#/components/schemas/WebhookTarget'
|
||||||
|
event_types:
|
||||||
|
type: array
|
||||||
|
description: List of activity event type codes this channel subscribes to.
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/NotificationEventType'
|
||||||
|
example: [ "user.join", "peer.user.add", "peer.login.expire" ]
|
||||||
|
enabled:
|
||||||
|
type: boolean
|
||||||
|
description: Whether this notification channel is active.
|
||||||
|
example: true
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
- event_types
|
||||||
|
- enabled
|
||||||
|
NotificationChannelResponse:
|
||||||
|
type: object
|
||||||
|
description: A notification channel configuration.
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
description: Unique identifier of the notification channel.
|
||||||
|
readOnly: true
|
||||||
|
example: "ch8i4ug6lnn4g9hqv7m0"
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/NotificationChannelType'
|
||||||
|
target:
|
||||||
|
description: |
|
||||||
|
Channel-specific target configuration. The shape depends on the `type` field:
|
||||||
|
- `email`: an `EmailTarget` object
|
||||||
|
- `webhook`: a `WebhookTarget` object
|
||||||
|
oneOf:
|
||||||
|
- $ref: '#/components/schemas/EmailTarget'
|
||||||
|
- $ref: '#/components/schemas/WebhookTarget'
|
||||||
|
event_types:
|
||||||
|
type: array
|
||||||
|
description: List of activity event type codes this channel subscribes to.
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/NotificationEventType'
|
||||||
|
example: [ "user.join", "peer.user.add", "peer.login.expire" ]
|
||||||
|
enabled:
|
||||||
|
type: boolean
|
||||||
|
description: Whether this notification channel is active.
|
||||||
|
example: true
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- type
|
||||||
|
- event_types
|
||||||
|
- enabled
|
||||||
|
NotificationTypeEntry:
|
||||||
|
type: object
|
||||||
|
description: A map of event type codes to their human-readable descriptions.
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
user.join: "User joined"
|
||||||
BypassResponse:
|
BypassResponse:
|
||||||
type: object
|
type: object
|
||||||
description: Response for bypassed peer operations.
|
description: Response for bypassed peer operations.
|
||||||
@@ -8321,6 +8597,241 @@ paths:
|
|||||||
$ref: "#/components/responses/requires_authentication"
|
$ref: "#/components/responses/requires_authentication"
|
||||||
"500":
|
"500":
|
||||||
$ref: "#/components/responses/internal_error"
|
$ref: "#/components/responses/internal_error"
|
||||||
|
/api/integrations/msp:
|
||||||
|
get:
|
||||||
|
summary: Get MSP or Tenant status
|
||||||
|
description: Returns the MSP, Tenant, or Reseller status of the authenticated account
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: MSP or Tenant status response
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/MSPStatusResponse"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
|
post:
|
||||||
|
summary: Create MSP account
|
||||||
|
description: Activates the authenticated account as an MSP
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
invite:
|
||||||
|
type: string
|
||||||
|
description: The invite code
|
||||||
|
example: "705860a1-27a3-4976-bf63-c5cd2fc1582b"
|
||||||
|
required:
|
||||||
|
- invite
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: MSP account created or already exists
|
||||||
|
"400":
|
||||||
|
$ref: "#/components/responses/bad_request"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/forbidden"
|
||||||
|
"412":
|
||||||
|
description: MSP account requirements not met
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
|
/api/integrations/msp/reseller:
|
||||||
|
get:
|
||||||
|
summary: Get Reseller status
|
||||||
|
description: Returns the reseller status of the authenticated account
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Reseller status response
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ResellerStatusResponse"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
|
/api/integrations/msp/reseller/msps:
|
||||||
|
get:
|
||||||
|
summary: List MSPs under reseller
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: List of MSPs managed by the reseller
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/GetResellerMSPsResponse"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/forbidden"
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
|
post:
|
||||||
|
summary: Create MSP under reseller
|
||||||
|
description: Creates a new MSP account managed by the reseller. No domain validation required.
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/CreateResellerMSPRequest"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: MSP created successfully
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ResellerMSPResponse"
|
||||||
|
"400":
|
||||||
|
$ref: "#/components/responses/bad_request"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/forbidden"
|
||||||
|
"409":
|
||||||
|
description: MSP already exists for this domain
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
|
/api/integrations/msp/reseller/msps/{id}:
|
||||||
|
put:
|
||||||
|
summary: Update MSP fields managed by reseller
|
||||||
|
description: Update editable reseller-level fields on an MSP (e.g. reseller_customer_id)
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: The MSP account ID to update
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/UpdateResellerMSPRequest"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: MSP updated successfully
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/ResellerMSPResponse"
|
||||||
|
"400":
|
||||||
|
$ref: "#/components/responses/bad_request"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/forbidden"
|
||||||
|
"404":
|
||||||
|
description: MSP not found or not managed by this reseller
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
|
delete:
|
||||||
|
summary: Unlink MSP from reseller
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: The MSP account ID to unlink
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: MSP unlinked successfully
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/forbidden"
|
||||||
|
"404":
|
||||||
|
description: MSP not found or not managed by this reseller
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
|
/api/integrations/msp/reseller/msps/{id}/invite:
|
||||||
|
post:
|
||||||
|
summary: Invite existing MSP to reseller
|
||||||
|
description: Sends an invitation to an existing MSP to join the reseller
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: The MSP account ID to invite
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Invitation sent successfully
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/forbidden"
|
||||||
|
"404":
|
||||||
|
description: MSP not found
|
||||||
|
"412":
|
||||||
|
description: MSP is already managed by a reseller
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
|
put:
|
||||||
|
summary: Accept or decline reseller invitation
|
||||||
|
description: MSP owner accepts or declines an invitation from a reseller
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: The MSP account ID
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
value:
|
||||||
|
type: string
|
||||||
|
description: Accept or decline the invitation
|
||||||
|
enum:
|
||||||
|
- accept
|
||||||
|
- decline
|
||||||
|
required:
|
||||||
|
- value
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Invitation response processed
|
||||||
|
"400":
|
||||||
|
$ref: "#/components/responses/bad_request"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/forbidden"
|
||||||
|
"404":
|
||||||
|
description: MSP not found or no pending invitation
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
/api/integrations/msp/tenants:
|
/api/integrations/msp/tenants:
|
||||||
get:
|
get:
|
||||||
summary: Get MSP tenants
|
summary: Get MSP tenants
|
||||||
@@ -8558,6 +9069,165 @@ paths:
|
|||||||
description: The tenant was not found
|
description: The tenant was not found
|
||||||
"500":
|
"500":
|
||||||
$ref: "#/components/responses/internal_error"
|
$ref: "#/components/responses/internal_error"
|
||||||
|
/api/integrations/msp/reseller/msps/{id}/subscription:
|
||||||
|
post:
|
||||||
|
summary: Create MSP subscription under reseller
|
||||||
|
description: Creates a managed Stripe subscription for an MSP managed by the reseller
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: The MSP account ID
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
priceID:
|
||||||
|
type: string
|
||||||
|
description: The Stripe price ID for the plan
|
||||||
|
required:
|
||||||
|
- priceID
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Subscription created successfully
|
||||||
|
"400":
|
||||||
|
$ref: "#/components/responses/bad_request"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/forbidden"
|
||||||
|
"404":
|
||||||
|
description: MSP not found or not managed by this reseller
|
||||||
|
"412":
|
||||||
|
description: MSP already has an active subscription or reseller has no subscription
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
|
put:
|
||||||
|
summary: Change MSP subscription plan
|
||||||
|
description: Changes the plan of an MSP subscription managed by the reseller
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: The MSP account ID
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
priceID:
|
||||||
|
type: string
|
||||||
|
description: The new Stripe price ID
|
||||||
|
required:
|
||||||
|
- priceID
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Subscription updated successfully
|
||||||
|
"400":
|
||||||
|
$ref: "#/components/responses/bad_request"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/forbidden"
|
||||||
|
"404":
|
||||||
|
description: MSP not found or not managed by this reseller
|
||||||
|
"412":
|
||||||
|
description: Subscription was recently updated
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
|
/api/integrations/msp/reseller/invoices:
|
||||||
|
get:
|
||||||
|
summary: List reseller invoices
|
||||||
|
description: Returns paid invoices for the reseller account
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: List of paid invoices
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/InvoiceResponse"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/forbidden"
|
||||||
|
"404":
|
||||||
|
description: No invoices found
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
|
/api/integrations/msp/reseller/invoices/{invoiceId}/pdf:
|
||||||
|
get:
|
||||||
|
summary: Get reseller invoice PDF
|
||||||
|
description: Returns the Stripe hosted URL for a reseller invoice
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: invoiceId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: The Stripe invoice ID
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Invoice PDF URL
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/InvoicePDFResponse"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/forbidden"
|
||||||
|
"404":
|
||||||
|
description: Invoice not found
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
|
/api/integrations/msp/reseller/invoices/{invoiceId}/csv:
|
||||||
|
get:
|
||||||
|
summary: Get reseller invoice CSV
|
||||||
|
description: Returns the invoice data as CSV
|
||||||
|
tags:
|
||||||
|
- MSP
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: invoiceId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description: The Stripe invoice ID
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: CSV file
|
||||||
|
content:
|
||||||
|
text/csv:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: binary
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/requires_authentication"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/forbidden"
|
||||||
|
"404":
|
||||||
|
description: Invoice not found
|
||||||
|
"500":
|
||||||
|
$ref: "#/components/responses/internal_error"
|
||||||
/api/integrations/edr/intune:
|
/api/integrations/edr/intune:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -10062,3 +10732,172 @@ paths:
|
|||||||
"$ref": "#/components/responses/not_found"
|
"$ref": "#/components/responses/not_found"
|
||||||
'500':
|
'500':
|
||||||
"$ref": "#/components/responses/internal_error"
|
"$ref": "#/components/responses/internal_error"
|
||||||
|
/api/integrations/notifications/types:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Notifications
|
||||||
|
summary: List Notification Event Types
|
||||||
|
description: |
|
||||||
|
Returns a map of all supported activity event type codes to their
|
||||||
|
human-readable descriptions. Use these codes when configuring
|
||||||
|
`event_types` on notification channels.
|
||||||
|
operationId: listNotificationEventTypes
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: A map of event type codes to descriptions.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/NotificationTypeEntry'
|
||||||
|
'400':
|
||||||
|
"$ref": "#/components/responses/bad_request"
|
||||||
|
'401':
|
||||||
|
"$ref": "#/components/responses/requires_authentication"
|
||||||
|
'403':
|
||||||
|
"$ref": "#/components/responses/forbidden"
|
||||||
|
'404':
|
||||||
|
"$ref": "#/components/responses/not_found"
|
||||||
|
'500':
|
||||||
|
"$ref": "#/components/responses/internal_error"
|
||||||
|
/api/integrations/notifications/channels:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Notifications
|
||||||
|
summary: List Notification Channels
|
||||||
|
description: Retrieves all notification channels configured for the authenticated account.
|
||||||
|
operationId: listNotificationChannels
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: A list of notification channels.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/NotificationChannelResponse'
|
||||||
|
'400':
|
||||||
|
"$ref": "#/components/responses/bad_request"
|
||||||
|
'401':
|
||||||
|
"$ref": "#/components/responses/requires_authentication"
|
||||||
|
'403':
|
||||||
|
"$ref": "#/components/responses/forbidden"
|
||||||
|
'404':
|
||||||
|
"$ref": "#/components/responses/not_found"
|
||||||
|
'500':
|
||||||
|
"$ref": "#/components/responses/internal_error"
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Notifications
|
||||||
|
summary: Create Notification Channel
|
||||||
|
description: |
|
||||||
|
Creates a new notification channel for the authenticated account.
|
||||||
|
Supported channel types are `email` and `webhook`.
|
||||||
|
operationId: createNotificationChannel
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/NotificationChannelRequest'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Notification channel created successfully.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/NotificationChannelResponse'
|
||||||
|
'400':
|
||||||
|
"$ref": "#/components/responses/bad_request"
|
||||||
|
'401':
|
||||||
|
"$ref": "#/components/responses/requires_authentication"
|
||||||
|
'403':
|
||||||
|
"$ref": "#/components/responses/forbidden"
|
||||||
|
'404':
|
||||||
|
"$ref": "#/components/responses/not_found"
|
||||||
|
'500':
|
||||||
|
"$ref": "#/components/responses/internal_error"
|
||||||
|
/api/integrations/notifications/channels/{channelId}:
|
||||||
|
parameters:
|
||||||
|
- name: channelId
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: The unique identifier of the notification channel.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: "ch8i4ug6lnn4g9hqv7m0"
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Notifications
|
||||||
|
summary: Get Notification Channel
|
||||||
|
description: Retrieves a specific notification channel by its ID.
|
||||||
|
operationId: getNotificationChannel
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Successfully retrieved the notification channel.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/NotificationChannelResponse'
|
||||||
|
'400':
|
||||||
|
"$ref": "#/components/responses/bad_request"
|
||||||
|
'401':
|
||||||
|
"$ref": "#/components/responses/requires_authentication"
|
||||||
|
'403':
|
||||||
|
"$ref": "#/components/responses/forbidden"
|
||||||
|
'404':
|
||||||
|
"$ref": "#/components/responses/not_found"
|
||||||
|
'500':
|
||||||
|
"$ref": "#/components/responses/internal_error"
|
||||||
|
put:
|
||||||
|
tags:
|
||||||
|
- Notifications
|
||||||
|
summary: Update Notification Channel
|
||||||
|
description: Updates an existing notification channel.
|
||||||
|
operationId: updateNotificationChannel
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/NotificationChannelRequest'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Notification channel updated successfully.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/NotificationChannelResponse'
|
||||||
|
'400':
|
||||||
|
"$ref": "#/components/responses/bad_request"
|
||||||
|
'401':
|
||||||
|
"$ref": "#/components/responses/requires_authentication"
|
||||||
|
'403':
|
||||||
|
"$ref": "#/components/responses/forbidden"
|
||||||
|
'404':
|
||||||
|
"$ref": "#/components/responses/not_found"
|
||||||
|
'500':
|
||||||
|
"$ref": "#/components/responses/internal_error"
|
||||||
|
delete:
|
||||||
|
tags:
|
||||||
|
- Notifications
|
||||||
|
summary: Delete Notification Channel
|
||||||
|
description: Deletes a notification channel by its ID.
|
||||||
|
operationId: deleteNotificationChannel
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Notification channel deleted successfully.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
example: { }
|
||||||
|
'400':
|
||||||
|
"$ref": "#/components/responses/bad_request"
|
||||||
|
'401':
|
||||||
|
"$ref": "#/components/responses/requires_authentication"
|
||||||
|
'403':
|
||||||
|
"$ref": "#/components/responses/forbidden"
|
||||||
|
'404':
|
||||||
|
"$ref": "#/components/responses/not_found"
|
||||||
|
'500':
|
||||||
|
"$ref": "#/components/responses/internal_error"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/oapi-codegen/runtime"
|
"github.com/oapi-codegen/runtime"
|
||||||
|
openapi_types "github.com/oapi-codegen/runtime/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -628,6 +629,30 @@ func (e JobResponseStatus) Valid() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defines values for MSPStatusResponseStatus.
|
||||||
|
const (
|
||||||
|
MSPStatusResponseStatusActive MSPStatusResponseStatus = "active"
|
||||||
|
MSPStatusResponseStatusExisting MSPStatusResponseStatus = "existing"
|
||||||
|
MSPStatusResponseStatusInvited MSPStatusResponseStatus = "invited"
|
||||||
|
MSPStatusResponseStatusPending MSPStatusResponseStatus = "pending"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Valid indicates whether the value is a known member of the MSPStatusResponseStatus enum.
|
||||||
|
func (e MSPStatusResponseStatus) Valid() bool {
|
||||||
|
switch e {
|
||||||
|
case MSPStatusResponseStatusActive:
|
||||||
|
return true
|
||||||
|
case MSPStatusResponseStatusExisting:
|
||||||
|
return true
|
||||||
|
case MSPStatusResponseStatusInvited:
|
||||||
|
return true
|
||||||
|
case MSPStatusResponseStatusPending:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Defines values for NameserverNsType.
|
// Defines values for NameserverNsType.
|
||||||
const (
|
const (
|
||||||
NameserverNsTypeUdp NameserverNsType = "udp"
|
NameserverNsTypeUdp NameserverNsType = "udp"
|
||||||
@@ -664,6 +689,24 @@ func (e NetworkResourceType) Valid() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defines values for NotificationChannelType.
|
||||||
|
const (
|
||||||
|
NotificationChannelTypeEmail NotificationChannelType = "email"
|
||||||
|
NotificationChannelTypeWebhook NotificationChannelType = "webhook"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Valid indicates whether the value is a known member of the NotificationChannelType enum.
|
||||||
|
func (e NotificationChannelType) Valid() bool {
|
||||||
|
switch e {
|
||||||
|
case NotificationChannelTypeEmail:
|
||||||
|
return true
|
||||||
|
case NotificationChannelTypeWebhook:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Defines values for PeerNetworkRangeCheckAction.
|
// Defines values for PeerNetworkRangeCheckAction.
|
||||||
const (
|
const (
|
||||||
PeerNetworkRangeCheckActionAllow PeerNetworkRangeCheckAction = "allow"
|
PeerNetworkRangeCheckActionAllow PeerNetworkRangeCheckAction = "allow"
|
||||||
@@ -1258,6 +1301,24 @@ func (e GetApiEventsProxyParamsStatus) Valid() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defines values for PutApiIntegrationsMspResellerMspsIdInviteJSONBodyValue.
|
||||||
|
const (
|
||||||
|
PutApiIntegrationsMspResellerMspsIdInviteJSONBodyValueAccept PutApiIntegrationsMspResellerMspsIdInviteJSONBodyValue = "accept"
|
||||||
|
PutApiIntegrationsMspResellerMspsIdInviteJSONBodyValueDecline PutApiIntegrationsMspResellerMspsIdInviteJSONBodyValue = "decline"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Valid indicates whether the value is a known member of the PutApiIntegrationsMspResellerMspsIdInviteJSONBodyValue enum.
|
||||||
|
func (e PutApiIntegrationsMspResellerMspsIdInviteJSONBodyValue) Valid() bool {
|
||||||
|
switch e {
|
||||||
|
case PutApiIntegrationsMspResellerMspsIdInviteJSONBodyValueAccept:
|
||||||
|
return true
|
||||||
|
case PutApiIntegrationsMspResellerMspsIdInviteJSONBodyValueDecline:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Defines values for PutApiIntegrationsMspTenantsIdInviteJSONBodyValue.
|
// Defines values for PutApiIntegrationsMspTenantsIdInviteJSONBodyValue.
|
||||||
const (
|
const (
|
||||||
PutApiIntegrationsMspTenantsIdInviteJSONBodyValueAccept PutApiIntegrationsMspTenantsIdInviteJSONBodyValue = "accept"
|
PutApiIntegrationsMspTenantsIdInviteJSONBodyValueAccept PutApiIntegrationsMspTenantsIdInviteJSONBodyValue = "accept"
|
||||||
@@ -1572,6 +1633,21 @@ type CreateIntegrationRequest struct {
|
|||||||
// CreateIntegrationRequestPlatform The event streaming platform to integrate with (e.g., "datadog", "s3", "firehose"). This field is used for creation. For updates (PUT), this field, if sent, is ignored by the backend.
|
// CreateIntegrationRequestPlatform The event streaming platform to integrate with (e.g., "datadog", "s3", "firehose"). This field is used for creation. For updates (PUT), this field, if sent, is ignored by the backend.
|
||||||
type CreateIntegrationRequestPlatform string
|
type CreateIntegrationRequestPlatform string
|
||||||
|
|
||||||
|
// CreateResellerMSPRequest defines model for CreateResellerMSPRequest.
|
||||||
|
type CreateResellerMSPRequest struct {
|
||||||
|
// Domain The domain for the MSP
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
|
||||||
|
// Name The name for the MSP
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// PriceID Stripe price ID to set up managed subscription for the MSP
|
||||||
|
PriceID *string `json:"priceID,omitempty"`
|
||||||
|
|
||||||
|
// ResellerCustomerId Reseller's internal customer reference for this MSP
|
||||||
|
ResellerCustomerId *string `json:"reseller_customer_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// CreateScimIntegrationRequest Request payload for creating an SCIM IDP integration
|
// CreateScimIntegrationRequest Request payload for creating an SCIM IDP integration
|
||||||
type CreateScimIntegrationRequest struct {
|
type CreateScimIntegrationRequest struct {
|
||||||
// GroupPrefixes List of start_with string patterns for groups to sync
|
// GroupPrefixes List of start_with string patterns for groups to sync
|
||||||
@@ -1893,6 +1969,12 @@ type EDRSentinelOneResponse struct {
|
|||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmailTarget Target configuration for email notification channels.
|
||||||
|
type EmailTarget struct {
|
||||||
|
// Emails List of email addresses to send notifications to.
|
||||||
|
Emails []openapi_types.Email `json:"emails"`
|
||||||
|
}
|
||||||
|
|
||||||
// ErrorResponse Standard error response. Note: The exact structure of this error response is inferred from `util.WriteErrorResponse` and `util.WriteError` usage in the provided Go code, as a specific Go struct for errors was not provided.
|
// ErrorResponse Standard error response. Note: The exact structure of this error response is inferred from `util.WriteErrorResponse` and `util.WriteError` usage in the provided Go code, as a specific Go struct for errors was not provided.
|
||||||
type ErrorResponse struct {
|
type ErrorResponse struct {
|
||||||
// Message A human-readable error message.
|
// Message A human-readable error message.
|
||||||
@@ -1944,6 +2026,9 @@ type GeoLocationCheck struct {
|
|||||||
// GeoLocationCheckAction Action to take upon policy match
|
// GeoLocationCheckAction Action to take upon policy match
|
||||||
type GeoLocationCheckAction string
|
type GeoLocationCheckAction string
|
||||||
|
|
||||||
|
// GetResellerMSPsResponse defines model for GetResellerMSPsResponse.
|
||||||
|
type GetResellerMSPsResponse = []ResellerMSPResponse
|
||||||
|
|
||||||
// GetTenantsResponse defines model for GetTenantsResponse.
|
// GetTenantsResponse defines model for GetTenantsResponse.
|
||||||
type GetTenantsResponse = []TenantResponse
|
type GetTenantsResponse = []TenantResponse
|
||||||
|
|
||||||
@@ -2323,6 +2408,51 @@ type Location struct {
|
|||||||
CountryCode CountryCode `json:"country_code"`
|
CountryCode CountryCode `json:"country_code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MSPStatusResponse defines model for MSPStatusResponse.
|
||||||
|
type MSPStatusResponse struct {
|
||||||
|
// ActivatedAt MSP or Tenant activation timestamp in RFC3339 format
|
||||||
|
ActivatedAt *string `json:"activated_at,omitempty"`
|
||||||
|
|
||||||
|
// Domain MSP domain (present only for MSP accounts)
|
||||||
|
Domain *string `json:"domain,omitempty"`
|
||||||
|
|
||||||
|
// HasReseller Whether the MSP has a reseller (present only for MSP accounts)
|
||||||
|
HasReseller *bool `json:"has_reseller,omitempty"`
|
||||||
|
|
||||||
|
// Id Tenant account ID (present only for tenants)
|
||||||
|
Id *string `json:"id,omitempty"`
|
||||||
|
|
||||||
|
// InvitedAt Tenant invitation timestamp in RFC3339 format (present only for tenants)
|
||||||
|
InvitedAt *string `json:"invited_at,omitempty"`
|
||||||
|
|
||||||
|
// IsReseller Whether the account is a reseller
|
||||||
|
IsReseller *bool `json:"is_reseller,omitempty"`
|
||||||
|
|
||||||
|
// Name MSP name (present only for MSP accounts)
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
|
||||||
|
// Parent Parent MSP account ID (present only for tenants)
|
||||||
|
Parent *string `json:"parent,omitempty"`
|
||||||
|
|
||||||
|
// ParentDomain Parent MSP domain (present only for tenants)
|
||||||
|
ParentDomain *string `json:"parent_domain,omitempty"`
|
||||||
|
|
||||||
|
// ParentName Parent MSP name (present only for tenants)
|
||||||
|
ParentName *string `json:"parent_name,omitempty"`
|
||||||
|
|
||||||
|
// ParentOwnerEmail Parent MSP owner email
|
||||||
|
ParentOwnerEmail *string `json:"parent_owner_email,omitempty"`
|
||||||
|
|
||||||
|
// ParentOwnerName Parent MSP owner name
|
||||||
|
ParentOwnerName *string `json:"parent_owner_name,omitempty"`
|
||||||
|
|
||||||
|
// Status Tenant status (present only for tenants)
|
||||||
|
Status *MSPStatusResponseStatus `json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MSPStatusResponseStatus Tenant status (present only for tenants)
|
||||||
|
type MSPStatusResponseStatus string
|
||||||
|
|
||||||
// MinKernelVersionCheck Posture check with the kernel version
|
// MinKernelVersionCheck Posture check with the kernel version
|
||||||
type MinKernelVersionCheck struct {
|
type MinKernelVersionCheck struct {
|
||||||
// MinKernelVersion Minimum acceptable version
|
// MinKernelVersion Minimum acceptable version
|
||||||
@@ -2666,6 +2796,67 @@ type NetworkTrafficUser struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotificationChannelRequest Request body for creating or updating a notification channel.
|
||||||
|
type NotificationChannelRequest struct {
|
||||||
|
// Enabled Whether this notification channel is active.
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
|
||||||
|
// EventTypes List of activity event type codes this channel subscribes to.
|
||||||
|
EventTypes []NotificationEventType `json:"event_types"`
|
||||||
|
|
||||||
|
// Target Channel-specific target configuration. The shape depends on the `type` field:
|
||||||
|
// - `email`: requires an `EmailTarget` object
|
||||||
|
// - `webhook`: requires a `WebhookTarget` object
|
||||||
|
Target *NotificationChannelRequest_Target `json:"target,omitempty"`
|
||||||
|
|
||||||
|
// Type The type of notification channel.
|
||||||
|
Type NotificationChannelType `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotificationChannelRequest_Target Channel-specific target configuration. The shape depends on the `type` field:
|
||||||
|
// - `email`: requires an `EmailTarget` object
|
||||||
|
// - `webhook`: requires a `WebhookTarget` object
|
||||||
|
type NotificationChannelRequest_Target struct {
|
||||||
|
union json.RawMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotificationChannelResponse A notification channel configuration.
|
||||||
|
type NotificationChannelResponse struct {
|
||||||
|
// Enabled Whether this notification channel is active.
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
|
||||||
|
// EventTypes List of activity event type codes this channel subscribes to.
|
||||||
|
EventTypes []NotificationEventType `json:"event_types"`
|
||||||
|
|
||||||
|
// Id Unique identifier of the notification channel.
|
||||||
|
Id *string `json:"id,omitempty"`
|
||||||
|
|
||||||
|
// Target Channel-specific target configuration. The shape depends on the `type` field:
|
||||||
|
// - `email`: an `EmailTarget` object
|
||||||
|
// - `webhook`: a `WebhookTarget` object
|
||||||
|
Target *NotificationChannelResponse_Target `json:"target,omitempty"`
|
||||||
|
|
||||||
|
// Type The type of notification channel.
|
||||||
|
Type NotificationChannelType `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotificationChannelResponse_Target Channel-specific target configuration. The shape depends on the `type` field:
|
||||||
|
// - `email`: an `EmailTarget` object
|
||||||
|
// - `webhook`: a `WebhookTarget` object
|
||||||
|
type NotificationChannelResponse_Target struct {
|
||||||
|
union json.RawMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotificationChannelType The type of notification channel.
|
||||||
|
type NotificationChannelType string
|
||||||
|
|
||||||
|
// NotificationEventType An activity event type code. See `GET /api/integrations/notifications/types` for the full list
|
||||||
|
// of supported event types and their human-readable descriptions.
|
||||||
|
type NotificationEventType = string
|
||||||
|
|
||||||
|
// NotificationTypeEntry A map of event type codes to their human-readable descriptions.
|
||||||
|
type NotificationTypeEntry map[string]string
|
||||||
|
|
||||||
// OSVersionCheck Posture check for the version of operating system
|
// OSVersionCheck Posture check for the version of operating system
|
||||||
type OSVersionCheck struct {
|
type OSVersionCheck struct {
|
||||||
// Android Posture check for the version of operating system
|
// Android Posture check for the version of operating system
|
||||||
@@ -3388,6 +3579,48 @@ type ProxyCluster struct {
|
|||||||
ConnectedProxies int `json:"connected_proxies"`
|
ConnectedProxies int `json:"connected_proxies"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResellerMSPResponse defines model for ResellerMSPResponse.
|
||||||
|
type ResellerMSPResponse struct {
|
||||||
|
// ActivatedAt MSP activation timestamp in RFC3339 format
|
||||||
|
ActivatedAt *string `json:"activated_at,omitempty"`
|
||||||
|
|
||||||
|
// Domain The MSP domain
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
|
||||||
|
// HasReseller Whether the MSP is managed by a reseller
|
||||||
|
HasReseller bool `json:"has_reseller"`
|
||||||
|
|
||||||
|
// Id The MSP account ID
|
||||||
|
Id string `json:"id"`
|
||||||
|
|
||||||
|
// InvitedAt MSP invitation timestamp in RFC3339 format
|
||||||
|
InvitedAt *string `json:"invited_at,omitempty"`
|
||||||
|
|
||||||
|
// Name The MSP name
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// ResellerCustomerId Reseller's internal customer reference for this MSP
|
||||||
|
ResellerCustomerId *string `json:"reseller_customer_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResellerStatusResponse defines model for ResellerStatusResponse.
|
||||||
|
type ResellerStatusResponse struct {
|
||||||
|
// ActivatedAt Reseller activation timestamp in RFC3339 format
|
||||||
|
ActivatedAt *string `json:"activated_at,omitempty"`
|
||||||
|
|
||||||
|
// Domain Reseller domain
|
||||||
|
Domain *string `json:"domain,omitempty"`
|
||||||
|
|
||||||
|
// Name Reseller name
|
||||||
|
Name *string `json:"name,omitempty"`
|
||||||
|
|
||||||
|
// ParentOwnerEmail Reseller owner email
|
||||||
|
ParentOwnerEmail *string `json:"parent_owner_email,omitempty"`
|
||||||
|
|
||||||
|
// ParentOwnerName Reseller owner name
|
||||||
|
ParentOwnerName *string `json:"parent_owner_name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Resource defines model for Resource.
|
// Resource defines model for Resource.
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
// Id ID of the resource
|
// Id ID of the resource
|
||||||
@@ -3632,6 +3865,9 @@ type Service struct {
|
|||||||
|
|
||||||
// Targets List of target backends for this service
|
// Targets List of target backends for this service
|
||||||
Targets []ServiceTarget `json:"targets"`
|
Targets []ServiceTarget `json:"targets"`
|
||||||
|
|
||||||
|
// Terminated Whether the service has been terminated. Terminated services cannot be updated. Services that violate the Terms of Service will be terminated.
|
||||||
|
Terminated *bool `json:"terminated,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceMode Service mode. "http" for L7 reverse proxy, "tcp"/"udp"/"tls" for L4 passthrough.
|
// ServiceMode Service mode. "http" for L7 reverse proxy, "tcp"/"udp"/"tls" for L4 passthrough.
|
||||||
@@ -3996,6 +4232,12 @@ type TenantResponse struct {
|
|||||||
// TenantResponseStatus The status of the tenant
|
// TenantResponseStatus The status of the tenant
|
||||||
type TenantResponseStatus string
|
type TenantResponseStatus string
|
||||||
|
|
||||||
|
// UpdateResellerMSPRequest defines model for UpdateResellerMSPRequest.
|
||||||
|
type UpdateResellerMSPRequest struct {
|
||||||
|
// ResellerCustomerId Reseller's internal customer reference for this MSP
|
||||||
|
ResellerCustomerId *string `json:"reseller_customer_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateScimIntegrationRequest Request payload for updating an SCIM IDP integration
|
// UpdateScimIntegrationRequest Request payload for updating an SCIM IDP integration
|
||||||
type UpdateScimIntegrationRequest struct {
|
type UpdateScimIntegrationRequest struct {
|
||||||
// Enabled Indicates whether the integration is enabled
|
// Enabled Indicates whether the integration is enabled
|
||||||
@@ -4211,6 +4453,16 @@ type UserRequest struct {
|
|||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WebhookTarget Target configuration for webhook notification channels.
|
||||||
|
type WebhookTarget struct {
|
||||||
|
// Headers Custom HTTP headers sent with each webhook request.
|
||||||
|
// Values are write-only; in GET responses all values are masked.
|
||||||
|
Headers *map[string]string `json:"headers,omitempty"`
|
||||||
|
|
||||||
|
// Url The webhook endpoint URL to send notifications to.
|
||||||
|
Url string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
// WorkloadRequest defines model for WorkloadRequest.
|
// WorkloadRequest defines model for WorkloadRequest.
|
||||||
type WorkloadRequest struct {
|
type WorkloadRequest struct {
|
||||||
union json.RawMessage
|
union json.RawMessage
|
||||||
@@ -4423,6 +4675,33 @@ type PutApiIntegrationsBillingSubscriptionJSONBody struct {
|
|||||||
PriceID *string `json:"priceID,omitempty"`
|
PriceID *string `json:"priceID,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PostApiIntegrationsMspJSONBody defines parameters for PostApiIntegrationsMsp.
|
||||||
|
type PostApiIntegrationsMspJSONBody struct {
|
||||||
|
// Invite The invite code
|
||||||
|
Invite string `json:"invite"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutApiIntegrationsMspResellerMspsIdInviteJSONBody defines parameters for PutApiIntegrationsMspResellerMspsIdInvite.
|
||||||
|
type PutApiIntegrationsMspResellerMspsIdInviteJSONBody struct {
|
||||||
|
// Value Accept or decline the invitation
|
||||||
|
Value PutApiIntegrationsMspResellerMspsIdInviteJSONBodyValue `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutApiIntegrationsMspResellerMspsIdInviteJSONBodyValue defines parameters for PutApiIntegrationsMspResellerMspsIdInvite.
|
||||||
|
type PutApiIntegrationsMspResellerMspsIdInviteJSONBodyValue string
|
||||||
|
|
||||||
|
// PostApiIntegrationsMspResellerMspsIdSubscriptionJSONBody defines parameters for PostApiIntegrationsMspResellerMspsIdSubscription.
|
||||||
|
type PostApiIntegrationsMspResellerMspsIdSubscriptionJSONBody struct {
|
||||||
|
// PriceID The Stripe price ID for the plan
|
||||||
|
PriceID string `json:"priceID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutApiIntegrationsMspResellerMspsIdSubscriptionJSONBody defines parameters for PutApiIntegrationsMspResellerMspsIdSubscription.
|
||||||
|
type PutApiIntegrationsMspResellerMspsIdSubscriptionJSONBody struct {
|
||||||
|
// PriceID The new Stripe price ID
|
||||||
|
PriceID string `json:"priceID"`
|
||||||
|
}
|
||||||
|
|
||||||
// PutApiIntegrationsMspTenantsIdInviteJSONBody defines parameters for PutApiIntegrationsMspTenantsIdInvite.
|
// PutApiIntegrationsMspTenantsIdInviteJSONBody defines parameters for PutApiIntegrationsMspTenantsIdInvite.
|
||||||
type PutApiIntegrationsMspTenantsIdInviteJSONBody struct {
|
type PutApiIntegrationsMspTenantsIdInviteJSONBody struct {
|
||||||
// Value Accept or decline the invitation.
|
// Value Accept or decline the invitation.
|
||||||
@@ -4549,6 +4828,24 @@ type CreateSentinelOneEDRIntegrationJSONRequestBody = EDRSentinelOneRequest
|
|||||||
// UpdateSentinelOneEDRIntegrationJSONRequestBody defines body for UpdateSentinelOneEDRIntegration for application/json ContentType.
|
// UpdateSentinelOneEDRIntegrationJSONRequestBody defines body for UpdateSentinelOneEDRIntegration for application/json ContentType.
|
||||||
type UpdateSentinelOneEDRIntegrationJSONRequestBody = EDRSentinelOneRequest
|
type UpdateSentinelOneEDRIntegrationJSONRequestBody = EDRSentinelOneRequest
|
||||||
|
|
||||||
|
// PostApiIntegrationsMspJSONRequestBody defines body for PostApiIntegrationsMsp for application/json ContentType.
|
||||||
|
type PostApiIntegrationsMspJSONRequestBody PostApiIntegrationsMspJSONBody
|
||||||
|
|
||||||
|
// PostApiIntegrationsMspResellerMspsJSONRequestBody defines body for PostApiIntegrationsMspResellerMsps for application/json ContentType.
|
||||||
|
type PostApiIntegrationsMspResellerMspsJSONRequestBody = CreateResellerMSPRequest
|
||||||
|
|
||||||
|
// PutApiIntegrationsMspResellerMspsIdJSONRequestBody defines body for PutApiIntegrationsMspResellerMspsId for application/json ContentType.
|
||||||
|
type PutApiIntegrationsMspResellerMspsIdJSONRequestBody = UpdateResellerMSPRequest
|
||||||
|
|
||||||
|
// PutApiIntegrationsMspResellerMspsIdInviteJSONRequestBody defines body for PutApiIntegrationsMspResellerMspsIdInvite for application/json ContentType.
|
||||||
|
type PutApiIntegrationsMspResellerMspsIdInviteJSONRequestBody PutApiIntegrationsMspResellerMspsIdInviteJSONBody
|
||||||
|
|
||||||
|
// PostApiIntegrationsMspResellerMspsIdSubscriptionJSONRequestBody defines body for PostApiIntegrationsMspResellerMspsIdSubscription for application/json ContentType.
|
||||||
|
type PostApiIntegrationsMspResellerMspsIdSubscriptionJSONRequestBody PostApiIntegrationsMspResellerMspsIdSubscriptionJSONBody
|
||||||
|
|
||||||
|
// PutApiIntegrationsMspResellerMspsIdSubscriptionJSONRequestBody defines body for PutApiIntegrationsMspResellerMspsIdSubscription for application/json ContentType.
|
||||||
|
type PutApiIntegrationsMspResellerMspsIdSubscriptionJSONRequestBody PutApiIntegrationsMspResellerMspsIdSubscriptionJSONBody
|
||||||
|
|
||||||
// PostApiIntegrationsMspTenantsJSONRequestBody defines body for PostApiIntegrationsMspTenants for application/json ContentType.
|
// PostApiIntegrationsMspTenantsJSONRequestBody defines body for PostApiIntegrationsMspTenants for application/json ContentType.
|
||||||
type PostApiIntegrationsMspTenantsJSONRequestBody = CreateTenantRequest
|
type PostApiIntegrationsMspTenantsJSONRequestBody = CreateTenantRequest
|
||||||
|
|
||||||
@@ -4564,6 +4861,12 @@ type PostApiIntegrationsMspTenantsIdSubscriptionJSONRequestBody PostApiIntegrati
|
|||||||
// PostApiIntegrationsMspTenantsIdUnlinkJSONRequestBody defines body for PostApiIntegrationsMspTenantsIdUnlink for application/json ContentType.
|
// PostApiIntegrationsMspTenantsIdUnlinkJSONRequestBody defines body for PostApiIntegrationsMspTenantsIdUnlink for application/json ContentType.
|
||||||
type PostApiIntegrationsMspTenantsIdUnlinkJSONRequestBody PostApiIntegrationsMspTenantsIdUnlinkJSONBody
|
type PostApiIntegrationsMspTenantsIdUnlinkJSONRequestBody PostApiIntegrationsMspTenantsIdUnlinkJSONBody
|
||||||
|
|
||||||
|
// CreateNotificationChannelJSONRequestBody defines body for CreateNotificationChannel for application/json ContentType.
|
||||||
|
type CreateNotificationChannelJSONRequestBody = NotificationChannelRequest
|
||||||
|
|
||||||
|
// UpdateNotificationChannelJSONRequestBody defines body for UpdateNotificationChannel for application/json ContentType.
|
||||||
|
type UpdateNotificationChannelJSONRequestBody = NotificationChannelRequest
|
||||||
|
|
||||||
// CreateSCIMIntegrationJSONRequestBody defines body for CreateSCIMIntegration for application/json ContentType.
|
// CreateSCIMIntegrationJSONRequestBody defines body for CreateSCIMIntegration for application/json ContentType.
|
||||||
type CreateSCIMIntegrationJSONRequestBody = CreateScimIntegrationRequest
|
type CreateSCIMIntegrationJSONRequestBody = CreateScimIntegrationRequest
|
||||||
|
|
||||||
@@ -4660,6 +4963,130 @@ type PutApiUsersUserIdPasswordJSONRequestBody = PasswordChangeRequest
|
|||||||
// PostApiUsersUserIdTokensJSONRequestBody defines body for PostApiUsersUserIdTokens for application/json ContentType.
|
// PostApiUsersUserIdTokensJSONRequestBody defines body for PostApiUsersUserIdTokens for application/json ContentType.
|
||||||
type PostApiUsersUserIdTokensJSONRequestBody = PersonalAccessTokenRequest
|
type PostApiUsersUserIdTokensJSONRequestBody = PersonalAccessTokenRequest
|
||||||
|
|
||||||
|
// AsEmailTarget returns the union data inside the NotificationChannelRequest_Target as a EmailTarget
|
||||||
|
func (t NotificationChannelRequest_Target) AsEmailTarget() (EmailTarget, error) {
|
||||||
|
var body EmailTarget
|
||||||
|
err := json.Unmarshal(t.union, &body)
|
||||||
|
return body, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromEmailTarget overwrites any union data inside the NotificationChannelRequest_Target as the provided EmailTarget
|
||||||
|
func (t *NotificationChannelRequest_Target) FromEmailTarget(v EmailTarget) error {
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
t.union = b
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeEmailTarget performs a merge with any union data inside the NotificationChannelRequest_Target, using the provided EmailTarget
|
||||||
|
func (t *NotificationChannelRequest_Target) MergeEmailTarget(v EmailTarget) error {
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
merged, err := runtime.JSONMerge(t.union, b)
|
||||||
|
t.union = merged
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsWebhookTarget returns the union data inside the NotificationChannelRequest_Target as a WebhookTarget
|
||||||
|
func (t NotificationChannelRequest_Target) AsWebhookTarget() (WebhookTarget, error) {
|
||||||
|
var body WebhookTarget
|
||||||
|
err := json.Unmarshal(t.union, &body)
|
||||||
|
return body, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromWebhookTarget overwrites any union data inside the NotificationChannelRequest_Target as the provided WebhookTarget
|
||||||
|
func (t *NotificationChannelRequest_Target) FromWebhookTarget(v WebhookTarget) error {
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
t.union = b
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeWebhookTarget performs a merge with any union data inside the NotificationChannelRequest_Target, using the provided WebhookTarget
|
||||||
|
func (t *NotificationChannelRequest_Target) MergeWebhookTarget(v WebhookTarget) error {
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
merged, err := runtime.JSONMerge(t.union, b)
|
||||||
|
t.union = merged
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t NotificationChannelRequest_Target) MarshalJSON() ([]byte, error) {
|
||||||
|
b, err := t.union.MarshalJSON()
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *NotificationChannelRequest_Target) UnmarshalJSON(b []byte) error {
|
||||||
|
err := t.union.UnmarshalJSON(b)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsEmailTarget returns the union data inside the NotificationChannelResponse_Target as a EmailTarget
|
||||||
|
func (t NotificationChannelResponse_Target) AsEmailTarget() (EmailTarget, error) {
|
||||||
|
var body EmailTarget
|
||||||
|
err := json.Unmarshal(t.union, &body)
|
||||||
|
return body, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromEmailTarget overwrites any union data inside the NotificationChannelResponse_Target as the provided EmailTarget
|
||||||
|
func (t *NotificationChannelResponse_Target) FromEmailTarget(v EmailTarget) error {
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
t.union = b
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeEmailTarget performs a merge with any union data inside the NotificationChannelResponse_Target, using the provided EmailTarget
|
||||||
|
func (t *NotificationChannelResponse_Target) MergeEmailTarget(v EmailTarget) error {
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
merged, err := runtime.JSONMerge(t.union, b)
|
||||||
|
t.union = merged
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AsWebhookTarget returns the union data inside the NotificationChannelResponse_Target as a WebhookTarget
|
||||||
|
func (t NotificationChannelResponse_Target) AsWebhookTarget() (WebhookTarget, error) {
|
||||||
|
var body WebhookTarget
|
||||||
|
err := json.Unmarshal(t.union, &body)
|
||||||
|
return body, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromWebhookTarget overwrites any union data inside the NotificationChannelResponse_Target as the provided WebhookTarget
|
||||||
|
func (t *NotificationChannelResponse_Target) FromWebhookTarget(v WebhookTarget) error {
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
t.union = b
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeWebhookTarget performs a merge with any union data inside the NotificationChannelResponse_Target, using the provided WebhookTarget
|
||||||
|
func (t *NotificationChannelResponse_Target) MergeWebhookTarget(v WebhookTarget) error {
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
merged, err := runtime.JSONMerge(t.union, b)
|
||||||
|
t.union = merged
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t NotificationChannelResponse_Target) MarshalJSON() ([]byte, error) {
|
||||||
|
b, err := t.union.MarshalJSON()
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *NotificationChannelResponse_Target) UnmarshalJSON(b []byte) error {
|
||||||
|
err := t.union.UnmarshalJSON(b)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// AsBundleWorkloadRequest returns the union data inside the WorkloadRequest as a BundleWorkloadRequest
|
// AsBundleWorkloadRequest returns the union data inside the WorkloadRequest as a BundleWorkloadRequest
|
||||||
func (t WorkloadRequest) AsBundleWorkloadRequest() (BundleWorkloadRequest, error) {
|
func (t WorkloadRequest) AsBundleWorkloadRequest() (BundleWorkloadRequest, error) {
|
||||||
var body BundleWorkloadRequest
|
var body BundleWorkloadRequest
|
||||||
|
|||||||
Reference in New Issue
Block a user