From 50963a396ad4c64023c4e5d28b53b4a456f71eb4 Mon Sep 17 00:00:00 2001 From: Nikos Date: Thu, 4 Jan 2024 17:52:57 +0200 Subject: [PATCH 1/9] feat: use cobra for CLI --- Makefile | 2 +- cmd/root.go | 26 ++++++++++++++++++++++++++ cmd/{main.go => serve.go} | 30 +++++++++++++++++------------- cmd/version.go | 22 ++++++++++++++++++++++ go.mod | 3 +++ go.sum | 8 ++++++++ main.go | 7 +++++++ 7 files changed, 84 insertions(+), 14 deletions(-) create mode 100644 cmd/root.go rename cmd/{main.go => serve.go} (90%) create mode 100644 cmd/version.go create mode 100644 main.go diff --git a/Makefile b/Makefile index c190cbc48..e0b3de7e7 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ vendor: .PHONY: vendor build: cmd/ui/dist - $(MAKE) -C cmd build + $(GO) build -o $(GO_BIN) ./ .PHONY: build # plan is to use this as a probe, if folder is there target wont run and npm-build will skip diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 000000000..981dd7ebb --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,26 @@ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "", + Short: "Identity Platform Login UI", + Long: `A login UI for the Ory stack`, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { +} diff --git a/cmd/main.go b/cmd/serve.go similarity index 90% rename from cmd/main.go rename to cmd/serve.go index dd51438b4..14faf574e 100644 --- a/cmd/main.go +++ b/cmd/serve.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "context" @@ -9,6 +9,8 @@ import ( "os" "os/signal" + "github.com/spf13/cobra" + "syscall" "time" @@ -22,7 +24,6 @@ import ( "github.com/canonical/identity-platform-login-ui/internal/monitoring/prometheus" fga "github.com/canonical/identity-platform-login-ui/internal/openfga" "github.com/canonical/identity-platform-login-ui/internal/tracing" - "github.com/canonical/identity-platform-login-ui/internal/version" "github.com/canonical/identity-platform-login-ui/pkg/web" ) @@ -33,7 +34,20 @@ import ( //go:embed ui/dist/_next/static/*/*.css var jsFS embed.FS -func main() { +var serveCmd = &cobra.Command{ + Use: "serve", + Short: "serve starts the web server", + Long: `Launch the web application, list of environment variables is available in the readme`, + Run: func(cmd *cobra.Command, args []string) { + serve() + }, +} + +func init() { + rootCmd.AddCommand(serveCmd) +} + +func serve() { specs := new(config.EnvSpec) @@ -41,16 +55,6 @@ func main() { panic(fmt.Errorf("issues with environment sourcing: %s", err)) } - flags := config.NewFlags() - - switch { - case flags.ShowVersion: - fmt.Printf("App Version: %s\n", version.Version) - os.Exit(0) - default: - break - } - logger := logging.NewLogger(specs.LogLevel, specs.LogFile) logger.Debugf("env vars: %v", specs) diff --git a/cmd/version.go b/cmd/version.go new file mode 100644 index 000000000..dc1df97da --- /dev/null +++ b/cmd/version.go @@ -0,0 +1,22 @@ +package cmd + +import ( + "fmt" + + "github.com/canonical/identity-platform-login-ui/internal/version" + "github.com/spf13/cobra" +) + +// versionCmd represents the version command +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Get the application's version", + Long: `Get the application's version`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("App Version: %s\n", version.Version) + }, +} + +func init() { + rootCmd.AddCommand(versionCmd) +} diff --git a/go.mod b/go.mod index 95e32c51b..27eb29137 100644 --- a/go.mod +++ b/go.mod @@ -35,11 +35,14 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect + github.com/spf13/cobra v1.8.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect go.opentelemetry.io/otel/metric v1.19.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.10.0 // indirect diff --git a/go.sum b/go.sum index 0b5b754d0..fbf6b3120 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,7 @@ github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqy github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= @@ -29,6 +30,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww= github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= @@ -57,6 +60,11 @@ github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwa github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= diff --git a/main.go b/main.go new file mode 100644 index 000000000..cae361662 --- /dev/null +++ b/main.go @@ -0,0 +1,7 @@ +package main + +import "github.com/canonical/identity-platform-login-ui/cmd" + +func main() { + cmd.Execute() +} From d2f65fc35bb53b938beeca70132851e3674ec217 Mon Sep 17 00:00:00 2001 From: Nikos Date: Fri, 5 Jan 2024 15:01:05 +0200 Subject: [PATCH 2/9] fix: bump otel/trace version --- go.mod | 12 ++++++------ go.sum | 12 ++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 27eb29137..6962ef112 100644 --- a/go.mod +++ b/go.mod @@ -13,13 +13,13 @@ require ( github.com/stretchr/testify v1.8.4 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 go.opentelemetry.io/contrib/propagators/jaeger v1.20.0 - go.opentelemetry.io/otel v1.19.0 + go.opentelemetry.io/otel v1.21.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0 - go.opentelemetry.io/otel/sdk v1.19.0 - go.opentelemetry.io/otel/trace v1.19.0 + go.opentelemetry.io/otel/sdk v1.21.0 + go.opentelemetry.io/otel/trace v1.21.0 go.uber.org/mock v0.3.0 go.uber.org/zap v1.26.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 @@ -31,7 +31,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect @@ -43,13 +43,13 @@ require ( github.com/prometheus/procfs v0.11.1 // indirect github.com/spf13/cobra v1.8.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/net v0.14.0 // indirect golang.org/x/oauth2 v0.11.0 // indirect golang.org/x/sync v0.4.0 // indirect - golang.org/x/sys v0.12.0 // indirect + golang.org/x/sys v0.14.0 // indirect golang.org/x/text v0.12.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect diff --git a/go.sum b/go.sum index fbf6b3120..c6d831e2f 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,8 @@ github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vz github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= @@ -73,6 +75,8 @@ go.opentelemetry.io/contrib/propagators/jaeger v1.20.0 h1:iVhNKkMIpzyZqxk8jkDU2n go.opentelemetry.io/contrib/propagators/jaeger v1.20.0/go.mod h1:cpSABr0cm/AH/HhbJjn+AudBVUMgZWdfN3Gb+ZqxSZc= go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= 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/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= @@ -83,10 +87,16 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0 h1:Nw7Dv4lwvGrI68+ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0/go.mod h1:1MsF6Y7gTqosgoZvHlzcaaM8DIMNZgJh87ykokoNH7Y= go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= 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.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= @@ -109,6 +119,8 @@ golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= From 5b6f62a9ce35cdd5c79463c34fe780a64aa3fbe1 Mon Sep 17 00:00:00 2001 From: Nikos Date: Thu, 4 Jan 2024 18:06:31 +0200 Subject: [PATCH 3/9] fix: add noop clients --- internal/authorization/authorization.go | 14 +++++++-- internal/healthcheck/checkers.go | 6 ++-- internal/logging/noop.go | 19 +++++++++++ internal/monitoring/noop.go | 28 +++++++++++++++++ internal/openfga/client.go | 8 ++--- internal/openfga/noop.go | 10 ++++-- internal/tracing/config.go | 6 ++++ internal/tracing/interfaces.go | 11 +++++++ internal/tracing/noop.go | 27 ++++++++++++++++ internal/tracing/tracer.go | 7 ++++- pkg/extra/service.go | 6 ++-- pkg/extra/service_test.go | 14 ++++----- pkg/kratos/service.go | 6 ++-- pkg/kratos/service_test.go | 42 ++++++++++++------------- pkg/status/handlers.go | 6 ++-- pkg/status/handlers_test.go | 8 ++--- pkg/status/service.go | 6 ++-- pkg/status/service_test.go | 10 +++--- pkg/web/router.go | 3 +- 19 files changed, 172 insertions(+), 65 deletions(-) create mode 100644 internal/logging/noop.go create mode 100644 internal/monitoring/noop.go create mode 100644 internal/tracing/interfaces.go create mode 100644 internal/tracing/noop.go diff --git a/internal/authorization/authorization.go b/internal/authorization/authorization.go index 9f490fd22..5635005b0 100644 --- a/internal/authorization/authorization.go +++ b/internal/authorization/authorization.go @@ -7,8 +7,8 @@ import ( "github.com/canonical/identity-platform-login-ui/internal/logging" "github.com/canonical/identity-platform-login-ui/internal/monitoring" + "github.com/canonical/identity-platform-login-ui/internal/tracing" fga "github.com/openfga/go-sdk" - "go.opentelemetry.io/otel/trace" ) var ErrInvalidAuthModel = fmt.Errorf("Invalid authorization model schema") @@ -16,7 +16,7 @@ var ErrInvalidAuthModel = fmt.Errorf("Invalid authorization model schema") type Authorizer struct { Client AuthzClientInterface - tracer trace.Tracer + tracer tracing.TracingInterface monitor monitoring.MonitorInterface logger logging.LoggerInterface } @@ -53,6 +53,14 @@ func (a *Authorizer) FilterObjects(ctx context.Context, user string, relation st return ret, nil } +func (a *Authorizer) CreateModel(ctx context.Context) (string, error) { + ctx, span := a.tracer.Start(ctx, "authorization.Authorizer.CreateModel") + defer span.End() + + modelId, err := a.Client.WriteModel(ctx, []byte(authModel)) + return modelId, err +} + func (a *Authorizer) ValidateModel(ctx context.Context) error { ctx, span := a.tracer.Start(ctx, "authorization.Authorizer.ValidateModel") defer span.End() @@ -73,7 +81,7 @@ func (a *Authorizer) ValidateModel(ctx context.Context) error { return nil } -func NewAuthorizer(client AuthzClientInterface, tracer trace.Tracer, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *Authorizer { +func NewAuthorizer(client AuthzClientInterface, tracer tracing.TracingInterface, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *Authorizer { authorizer := new(Authorizer) authorizer.Client = client authorizer.tracer = tracer diff --git a/internal/healthcheck/checkers.go b/internal/healthcheck/checkers.go index 0ec49117c..9ae63dce8 100644 --- a/internal/healthcheck/checkers.go +++ b/internal/healthcheck/checkers.go @@ -7,7 +7,7 @@ import ( "time" "github.com/canonical/identity-platform-login-ui/internal/logging" - "go.opentelemetry.io/otel/trace" + "github.com/canonical/identity-platform-login-ui/internal/tracing" ) type CheckFunction func(context.Context) (bool, error) @@ -28,7 +28,7 @@ type Checker struct { shutdownCh chan bool - tracer trace.Tracer + tracer tracing.TracingInterface logger logging.LoggerInterface } @@ -77,7 +77,7 @@ func (c *Checker) loop() { } } -func NewChecker(f CheckFunction, tracer trace.Tracer, logger logging.LoggerInterface) *Checker { +func NewChecker(f CheckFunction, tracer tracing.TracingInterface, logger logging.LoggerInterface) *Checker { c := new(Checker) c.f = f c.shutdownCh = make(chan bool) diff --git a/internal/logging/noop.go b/internal/logging/noop.go new file mode 100644 index 000000000..d94be142a --- /dev/null +++ b/internal/logging/noop.go @@ -0,0 +1,19 @@ +package logging + +type NoopLogger struct { +} + +func NewNoopLogger() *NoopLogger { + return new(NoopLogger) +} + +func (l *NoopLogger) Errorf(string, ...interface{}) {} +func (l *NoopLogger) Infof(string, ...interface{}) {} +func (l *NoopLogger) Warnf(string, ...interface{}) {} +func (l *NoopLogger) Debugf(string, ...interface{}) {} +func (l *NoopLogger) Fatalf(string, ...interface{}) {} +func (l *NoopLogger) Error(...interface{}) {} +func (l *NoopLogger) Info(...interface{}) {} +func (l *NoopLogger) Warn(...interface{}) {} +func (l *NoopLogger) Debug(...interface{}) {} +func (l *NoopLogger) Fatal(...interface{}) {} diff --git a/internal/monitoring/noop.go b/internal/monitoring/noop.go new file mode 100644 index 000000000..646a66fb6 --- /dev/null +++ b/internal/monitoring/noop.go @@ -0,0 +1,28 @@ +package monitoring + +import ( + "github.com/canonical/identity-platform-login-ui/internal/logging" +) + +type NoopMonitor struct { + service string + + logger logging.LoggerInterface +} + +func NewNoopMonitor(service string, logger logging.LoggerInterface) *NoopMonitor { + m := new(NoopMonitor) + m.service = service + m.logger = logger + return m +} + +func (m *NoopMonitor) GetService() string { + return m.service +} +func (m *NoopMonitor) SetResponseTimeMetric(map[string]string, float64) error { + return nil +} +func (m *NoopMonitor) SetDependencyAvailability(map[string]string, float64) error { + return nil +} diff --git a/internal/openfga/client.go b/internal/openfga/client.go index 7d93a4349..e5c5c5bca 100644 --- a/internal/openfga/client.go +++ b/internal/openfga/client.go @@ -10,11 +10,11 @@ import ( "github.com/canonical/identity-platform-login-ui/internal/logging" "github.com/canonical/identity-platform-login-ui/internal/monitoring" + "github.com/canonical/identity-platform-login-ui/internal/tracing" openfga "github.com/openfga/go-sdk" "github.com/openfga/go-sdk/client" "github.com/openfga/go-sdk/credentials" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" - "go.opentelemetry.io/otel/trace" ) type Config struct { @@ -25,12 +25,12 @@ type Config struct { AuthModelID string Debug bool - Tracer trace.Tracer + Tracer tracing.TracingInterface Monitor monitoring.MonitorInterface Logger logging.LoggerInterface } -func NewConfig(apiScheme, apiHost, storeID, apiToken, authModelID string, debug bool, tracer trace.Tracer, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *Config { +func NewConfig(apiScheme, apiHost, storeID, apiToken, authModelID string, debug bool, tracer tracing.TracingInterface, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *Config { c := new(Config) c.ApiScheme = apiScheme @@ -50,7 +50,7 @@ func NewConfig(apiScheme, apiHost, storeID, apiToken, authModelID string, debug type Client struct { c *client.OpenFgaClient - tracer trace.Tracer + tracer tracing.TracingInterface monitor monitoring.MonitorInterface logger logging.LoggerInterface } diff --git a/internal/openfga/noop.go b/internal/openfga/noop.go index 2f6683811..2ede4cb5e 100644 --- a/internal/openfga/noop.go +++ b/internal/openfga/noop.go @@ -5,17 +5,17 @@ import ( "github.com/canonical/identity-platform-login-ui/internal/logging" "github.com/canonical/identity-platform-login-ui/internal/monitoring" + "github.com/canonical/identity-platform-login-ui/internal/tracing" openfga "github.com/openfga/go-sdk" - "go.opentelemetry.io/otel/trace" ) type NoopClient struct { - tracer trace.Tracer + tracer tracing.TracingInterface monitor monitoring.MonitorInterface logger logging.LoggerInterface } -func NewNoopClient(tracer trace.Tracer, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *NoopClient { +func NewNoopClient(tracer tracing.TracingInterface, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *NoopClient { c := new(NoopClient) c.tracer = tracer c.monitor = monitor @@ -35,6 +35,10 @@ func (c *NoopClient) ReadModel(ctx context.Context) (*openfga.AuthorizationModel return nil, nil } +func (c *NoopClient) WriteModel(ctx context.Context, model []byte) (string, error) { + return "", nil +} + func (c *NoopClient) CompareModel(ctx context.Context, model openfga.AuthorizationModel) (bool, error) { return true, nil } diff --git a/internal/tracing/config.go b/internal/tracing/config.go index d1b7dca49..c86875b27 100644 --- a/internal/tracing/config.go +++ b/internal/tracing/config.go @@ -22,3 +22,9 @@ func NewConfig(enabled bool, otelGRPCEndpoint, otelHTTPEndpoint string, logger l return c } + +func NewNoopConfig() *Config { + c := new(Config) + c.Enabled = false + return c +} diff --git a/internal/tracing/interfaces.go b/internal/tracing/interfaces.go new file mode 100644 index 000000000..5e9ea3ace --- /dev/null +++ b/internal/tracing/interfaces.go @@ -0,0 +1,11 @@ +package tracing + +import ( + "context" + + "go.opentelemetry.io/otel/trace" +) + +type TracingInterface interface { + Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) +} diff --git a/internal/tracing/noop.go b/internal/tracing/noop.go new file mode 100644 index 000000000..ebcc8e90e --- /dev/null +++ b/internal/tracing/noop.go @@ -0,0 +1,27 @@ +package tracing + +import ( + "context" + + "github.com/canonical/identity-platform-login-ui/internal/logging" + "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/embedded" + "go.opentelemetry.io/otel/trace/noop" +) + +type NoopTracer struct { + embedded.Tracer + tracer trace.Tracer + + logger logging.LoggerInterface +} + +func NewNoopTracer(cfg *Config) *NoopTracer { + t := new(NoopTracer) + t.tracer = new(noop.Tracer) + return t +} + +func (t *NoopTracer) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { + return t.tracer.Start(ctx, spanName, opts...) +} diff --git a/internal/tracing/tracer.go b/internal/tracing/tracer.go index 2cbd428e6..53080d911 100644 --- a/internal/tracing/tracer.go +++ b/internal/tracing/tracer.go @@ -17,6 +17,7 @@ import ( sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.18.0" "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" ) type Tracer struct { @@ -87,7 +88,7 @@ func NewTracer(cfg *Config) *Tracer { // if tracing disabled skip the config if !cfg.Enabled { - t.tracer = trace.NewNoopTracerProvider().Tracer("github.com/canonical/identity-platform-login-ui") + t.tracer = noop.NewTracerProvider().Tracer("github.com/canonical/identity-platform-login-ui") return t } @@ -128,3 +129,7 @@ func NewTracer(cfg *Config) *Tracer { return t } + +func NewNoopTracer() *Tracer { + return NewTracer(NewNoopConfig()) +} diff --git a/pkg/extra/service.go b/pkg/extra/service.go index ab2d4a9f1..0172b3ce2 100644 --- a/pkg/extra/service.go +++ b/pkg/extra/service.go @@ -7,7 +7,7 @@ import ( "github.com/canonical/identity-platform-login-ui/internal/logging" misc "github.com/canonical/identity-platform-login-ui/internal/misc/http" "github.com/canonical/identity-platform-login-ui/internal/monitoring" - "go.opentelemetry.io/otel/trace" + "github.com/canonical/identity-platform-login-ui/internal/tracing" hClient "github.com/ory/hydra-client-go/v2" kClient "github.com/ory/kratos-client-go" @@ -17,7 +17,7 @@ type Service struct { kratos KratosClientInterface hydra HydraClientInterface - tracer trace.Tracer + tracer tracing.TracingInterface monitor monitoring.MonitorInterface logger logging.LoggerInterface } @@ -89,7 +89,7 @@ func (s *Service) AcceptConsent(ctx context.Context, identity kClient.Identity, return accept, nil } -func NewService(kratos KratosClientInterface, hydra HydraClientInterface, tracer trace.Tracer, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *Service { +func NewService(kratos KratosClientInterface, hydra HydraClientInterface, tracer tracing.TracingInterface, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *Service { s := new(Service) s.kratos = kratos diff --git a/pkg/extra/service_test.go b/pkg/extra/service_test.go index 6c4d0e03f..cf0b6cbe1 100644 --- a/pkg/extra/service_test.go +++ b/pkg/extra/service_test.go @@ -17,7 +17,7 @@ import ( //go:generate mockgen -build_flags=--mod=mod -package extra -destination ./mock_logger.go -source=../../internal/logging/interfaces.go //go:generate mockgen -build_flags=--mod=mod -package extra -destination ./mock_extra.go -source=./interfaces.go //go:generate mockgen -build_flags=--mod=mod -package extra -destination ./mock_monitor.go -source=../../internal/monitoring/interfaces.go -//go:generate mockgen -build_flags=--mod=mod -package extra -destination ./mock_tracing.go go.opentelemetry.io/otel/trace Tracer +//go:generate mockgen -build_flags=--mod=mod -package extra -destination ./mock_tracing.go -source=../../internal/tracing/interfaces.go //go:generate mockgen -build_flags=--mod=mod -package extra -destination ./mock_kratos.go github.com/ory/kratos-client-go FrontendApi //go:generate mockgen -build_flags=--mod=mod -package extra -destination ./mock_hydra.go github.com/ory/hydra-client-go/v2 OAuth2Api @@ -28,7 +28,7 @@ func TestCheckSessionSuccess(t *testing.T) { mockLogger := NewMockLoggerInterface(ctrl) mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratosFrontendApi := NewMockFrontendApi(ctrl) @@ -72,7 +72,7 @@ func TestCheckSessionFails(t *testing.T) { mockLogger := NewMockLoggerInterface(ctrl) mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratosFrontendApi := NewMockFrontendApi(ctrl) @@ -116,7 +116,7 @@ func TestGetConsentSuccess(t *testing.T) { mockLogger := NewMockLoggerInterface(ctrl) mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockHydraOAuth2Api := NewMockOAuth2Api(ctrl) @@ -157,7 +157,7 @@ func TestGetConsentFails(t *testing.T) { mockLogger := NewMockLoggerInterface(ctrl) mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockHydraOAuth2Api := NewMockOAuth2Api(ctrl) @@ -199,7 +199,7 @@ func TestAcceptConsentSuccess(t *testing.T) { mockLogger := NewMockLoggerInterface(ctrl) mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockHydraOAuth2Api := NewMockOAuth2Api(ctrl) @@ -253,7 +253,7 @@ func TestAcceptConsentFails(t *testing.T) { mockLogger := NewMockLoggerInterface(ctrl) mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockHydraOAuth2Api := NewMockOAuth2Api(ctrl) diff --git a/pkg/kratos/service.go b/pkg/kratos/service.go index 3438f9bcd..b18e0487f 100644 --- a/pkg/kratos/service.go +++ b/pkg/kratos/service.go @@ -9,9 +9,9 @@ import ( "github.com/canonical/identity-platform-login-ui/internal/logging" "github.com/canonical/identity-platform-login-ui/internal/monitoring" + "github.com/canonical/identity-platform-login-ui/internal/tracing" hClient "github.com/ory/hydra-client-go/v2" kClient "github.com/ory/kratos-client-go" - "go.opentelemetry.io/otel/trace" ) type Service struct { @@ -19,7 +19,7 @@ type Service struct { hydra HydraClientInterface authz AuthorizerInterface - tracer trace.Tracer + tracer tracing.TracingInterface monitor monitoring.MonitorInterface logger logging.LoggerInterface } @@ -238,7 +238,7 @@ func (s *Service) contains(str []string, e string) bool { return false } -func NewService(kratos KratosClientInterface, hydra HydraClientInterface, authzClient AuthorizerInterface, tracer trace.Tracer, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *Service { +func NewService(kratos KratosClientInterface, hydra HydraClientInterface, authzClient AuthorizerInterface, tracer tracing.TracingInterface, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *Service { s := new(Service) s.kratos = kratos diff --git a/pkg/kratos/service_test.go b/pkg/kratos/service_test.go index 3a06a77a6..b11964fcf 100644 --- a/pkg/kratos/service_test.go +++ b/pkg/kratos/service_test.go @@ -21,7 +21,7 @@ import ( //go:generate mockgen -build_flags=--mod=mod -package kratos -destination ./mock_logger.go -source=../../internal/logging/interfaces.go //go:generate mockgen -build_flags=--mod=mod -package kratos -destination ./mock_interfaces.go -source=./interfaces.go //go:generate mockgen -build_flags=--mod=mod -package kratos -destination ./mock_monitor.go -source=../../internal/monitoring/interfaces.go -//go:generate mockgen -build_flags=--mod=mod -package kratos -destination ./mock_tracing.go go.opentelemetry.io/otel/trace Tracer +//go:generate mockgen -build_flags=--mod=mod -package kratos -destination ./mock_tracing.go -source=../../internal/tracing/interfaces.go //go:generate mockgen -build_flags=--mod=mod -package kratos -destination ./mock_kratos.go github.com/ory/kratos-client-go FrontendApi //go:generate mockgen -build_flags=--mod=mod -package kratos -destination ./mock_hydra.go github.com/ory/hydra-client-go/v2 OAuth2Api @@ -33,7 +33,7 @@ func TestCheckSessionSuccess(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratosFrontendApi := NewMockFrontendApi(ctrl) @@ -84,7 +84,7 @@ func TestCheckSessionFails(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratosFrontendApi := NewMockFrontendApi(ctrl) @@ -131,7 +131,7 @@ func TestAcceptLoginRequestSuccess(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockHydraOauthApi := NewMockOAuth2Api(ctrl) @@ -181,7 +181,7 @@ func TestAcceptLoginRequestFails(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockHydraOauthApi := NewMockOAuth2Api(ctrl) @@ -219,7 +219,7 @@ func TestCreateBrowserLoginFlowSuccess(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratosFrontendApi := NewMockFrontendApi(ctrl) @@ -285,7 +285,7 @@ func TestCreateBrowserLoginFlowFail(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratosFrontendApi := NewMockFrontendApi(ctrl) @@ -331,7 +331,7 @@ func TestGetLoginFlowSuccess(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratosFrontendApi := NewMockFrontendApi(ctrl) @@ -385,7 +385,7 @@ func TestGetLoginFlowFail(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratosFrontendApi := NewMockFrontendApi(ctrl) @@ -428,7 +428,7 @@ func TestUpdateLoginFlowSuccess(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratosFrontendApi := NewMockFrontendApi(ctrl) @@ -491,7 +491,7 @@ func TestUpdateLoginFlowFail(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratosFrontendApi := NewMockFrontendApi(ctrl) @@ -541,7 +541,7 @@ func TestGetFlowErrorSuccess(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratosFrontendApi := NewMockFrontendApi(ctrl) @@ -589,7 +589,7 @@ func TestGetFlowErrorFail(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratosFrontendApi := NewMockFrontendApi(ctrl) @@ -629,7 +629,7 @@ func TestCheckAllowedProviderAllowedSuccess(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) ctx := context.Background() @@ -667,7 +667,7 @@ func TestCheckAllowedProviderNotAllowedSuccess(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) ctx := context.Background() @@ -705,7 +705,7 @@ func TestCheckAllowedProviderFail(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) ctx := context.Background() @@ -739,7 +739,7 @@ func TestFilterFlowProviderListAllowAll(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) ctx := context.Background() @@ -785,7 +785,7 @@ func TestFilterFlowProviderListAllowSome(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) ctx := context.Background() @@ -834,7 +834,7 @@ func TestFilterFlowProviderListAllowNone(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) ctx := context.Background() @@ -881,7 +881,7 @@ func TestFilterFlowProviderListFail(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) ctx := context.Background() @@ -924,7 +924,7 @@ func TestParseLoginFlowMethodBody(t *testing.T) { mockHydra := NewMockHydraClientInterface(ctrl) mockKratos := NewMockKratosClientInterface(ctrl) mockAuthz := NewMockAuthorizerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) body := kClient.UpdateLoginFlowWithOidcMethodAsUpdateLoginFlowBody(kClient.NewUpdateLoginFlowWithOidcMethodWithDefaults()) diff --git a/pkg/status/handlers.go b/pkg/status/handlers.go index 1290efe28..c8ad53b13 100644 --- a/pkg/status/handlers.go +++ b/pkg/status/handlers.go @@ -6,8 +6,8 @@ import ( "github.com/canonical/identity-platform-login-ui/internal/logging" "github.com/canonical/identity-platform-login-ui/internal/monitoring" + "github.com/canonical/identity-platform-login-ui/internal/tracing" "github.com/go-chi/chi/v5" - "go.opentelemetry.io/otel/trace" ) const okValue = "ok" @@ -25,7 +25,7 @@ type Health struct { type API struct { service ServiceInterface - tracer trace.Tracer + tracer tracing.TracingInterface monitor monitoring.MonitorInterface logger logging.LoggerInterface @@ -76,7 +76,7 @@ func (a *API) ready(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(health) } -func NewAPI(service ServiceInterface, tracer trace.Tracer, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *API { +func NewAPI(service ServiceInterface, tracer tracing.TracingInterface, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *API { a := new(API) a.service = service diff --git a/pkg/status/handlers_test.go b/pkg/status/handlers_test.go index f37d939c1..944340822 100644 --- a/pkg/status/handlers_test.go +++ b/pkg/status/handlers_test.go @@ -13,7 +13,7 @@ import ( //go:generate mockgen -build_flags=--mod=mod -package status -destination ./mock_logger.go -source=../../internal/logging/interfaces.go //go:generate mockgen -build_flags=--mod=mod -package status -destination ./mock_monitor.go -source=../../internal/monitoring/interfaces.go -//go:generate mockgen -build_flags=--mod=mod -package status -destination ./mock_tracing.go go.opentelemetry.io/otel/trace Tracer +//go:generate mockgen -build_flags=--mod=mod -package status -destination ./mock_tracing.go -source=../../internal/tracing/interfaces.go //go:generate mockgen -build_flags=--mod=mod -package status -destination ./mock_status.go -source=./interfaces.go func TestAliveOK(t *testing.T) { @@ -22,7 +22,7 @@ func TestAliveOK(t *testing.T) { mockLogger := NewMockLoggerInterface(ctrl) mockMonitor := NewMockMonitorInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockService := NewMockServiceInterface(ctrl) req := httptest.NewRequest(http.MethodGet, "/api/v0/status", nil) @@ -56,7 +56,7 @@ func TestHealthSuccess(t *testing.T) { mockLogger := NewMockLoggerInterface(ctrl) mockMonitor := NewMockMonitorInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockService := NewMockServiceInterface(ctrl) req := httptest.NewRequest(http.MethodGet, "/api/v0/ready", nil) @@ -93,7 +93,7 @@ func TestHealthFailure(t *testing.T) { mockLogger := NewMockLoggerInterface(ctrl) mockMonitor := NewMockMonitorInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockService := NewMockServiceInterface(ctrl) req := httptest.NewRequest(http.MethodGet, "/api/v0/ready", nil) diff --git a/pkg/status/service.go b/pkg/status/service.go index 29b3e9092..9d20ac86e 100644 --- a/pkg/status/service.go +++ b/pkg/status/service.go @@ -7,8 +7,8 @@ import ( "github.com/canonical/identity-platform-login-ui/internal/healthcheck" "github.com/canonical/identity-platform-login-ui/internal/logging" "github.com/canonical/identity-platform-login-ui/internal/monitoring" + "github.com/canonical/identity-platform-login-ui/internal/tracing" "github.com/canonical/identity-platform-login-ui/internal/version" - "go.opentelemetry.io/otel/trace" hClient "github.com/ory/hydra-client-go/v2" kClient "github.com/ory/kratos-client-go" @@ -27,7 +27,7 @@ type Service struct { hydraStatus healthcheck.CheckerInterface kratosStatus healthcheck.CheckerInterface - tracer trace.Tracer + tracer tracing.TracingInterface monitor monitoring.MonitorInterface logger logging.LoggerInterface } @@ -117,7 +117,7 @@ func (s *Service) gitRevision(ctx context.Context, settings []debug.BuildSetting return "n/a" } -func NewService(kratos kClient.MetadataApi, hydra hClient.MetadataApi, tracer trace.Tracer, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *Service { +func NewService(kratos kClient.MetadataApi, hydra hClient.MetadataApi, tracer tracing.TracingInterface, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) *Service { s := new(Service) s.kratos = kratos diff --git a/pkg/status/service_test.go b/pkg/status/service_test.go index efeb6dfc4..1bdf21f28 100644 --- a/pkg/status/service_test.go +++ b/pkg/status/service_test.go @@ -17,7 +17,7 @@ import ( //go:generate mockgen -build_flags=--mod=mod -package status -destination ./mock_logger.go -source=../../internal/logging/interfaces.go //go:generate mockgen -build_flags=--mod=mod -package status -destination ./mock_status.go -source=./interfaces.go //go:generate mockgen -build_flags=--mod=mod -package status -destination ./mock_monitor.go -source=../../internal/monitoring/interfaces.go -//go:generate mockgen -build_flags=--mod=mod -package status -destination ./mock_tracing.go go.opentelemetry.io/otel/trace Tracer +//go:generate mockgen -build_flags=--mod=mod -package status -destination ./mock_tracing.go -source=../../internal/tracing/interfaces.go //go:generate mockgen -build_flags=--mod=mod -package status -destination ./mock_kratos.go -mock_names MetadataApi=MockKratosMetadataApi github.com/ory/kratos-client-go MetadataApi //go:generate mockgen -build_flags=--mod=mod -package status -destination ./mock_hydra.go -mock_names MetadataApi=MockHydraMetadataApi "github.com/ory/hydra-client-go/v2" MetadataApi @@ -26,7 +26,7 @@ func TestKratosReadySuccess(t *testing.T) { defer ctrl.Finish() mockLogger := NewMockLoggerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratos := NewMockKratosMetadataApi(ctrl) mockHydra := NewMockHydraMetadataApi(ctrl) @@ -66,7 +66,7 @@ func TestHydraReadySuccess(t *testing.T) { defer ctrl.Finish() mockLogger := NewMockLoggerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratos := NewMockKratosMetadataApi(ctrl) mockHydra := NewMockHydraMetadataApi(ctrl) @@ -106,7 +106,7 @@ func TestKratosReadyFailure(t *testing.T) { defer ctrl.Finish() mockLogger := NewMockLoggerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratos := NewMockKratosMetadataApi(ctrl) mockHydra := NewMockHydraMetadataApi(ctrl) @@ -145,7 +145,7 @@ func TestHydraReadyFailure(t *testing.T) { defer ctrl.Finish() mockLogger := NewMockLoggerInterface(ctrl) - mockTracer := NewMockTracer(ctrl) + mockTracer := NewMockTracingInterface(ctrl) mockMonitor := monitoring.NewMockMonitorInterface(ctrl) mockKratos := NewMockKratosMetadataApi(ctrl) mockHydra := NewMockHydraMetadataApi(ctrl) diff --git a/pkg/web/router.go b/pkg/web/router.go index df8640085..75ae7a804 100644 --- a/pkg/web/router.go +++ b/pkg/web/router.go @@ -12,7 +12,6 @@ import ( "github.com/canonical/identity-platform-login-ui/internal/tracing" chi "github.com/go-chi/chi/v5" middleware "github.com/go-chi/chi/v5/middleware" - trace "go.opentelemetry.io/otel/trace" "github.com/canonical/identity-platform-login-ui/pkg/extra" "github.com/canonical/identity-platform-login-ui/pkg/kratos" @@ -21,7 +20,7 @@ import ( "github.com/canonical/identity-platform-login-ui/pkg/ui" ) -func NewRouter(kratosClient *ik.Client, hydraClient *ih.Client, authzClient authz.AuthorizerInterface, distFS fs.FS, baseURL string, tracer trace.Tracer, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) http.Handler { +func NewRouter(kratosClient *ik.Client, hydraClient *ih.Client, authzClient authz.AuthorizerInterface, distFS fs.FS, baseURL string, tracer tracing.TracingInterface, monitor monitoring.MonitorInterface, logger logging.LoggerInterface) http.Handler { router := chi.NewMux() middlewares := make(chi.Middlewares, 0) From 80de6dd598c6a5b778ea43123bf9bc32b185aec1 Mon Sep 17 00:00:00 2001 From: Nikos Date: Fri, 5 Jan 2024 14:53:58 +0200 Subject: [PATCH 4/9] fix: readme typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0cbdd06a2..817344d91 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ CLIENT_SECRET= Run the login UI's dependencies: ```console -docker-compose -f docker-compose.dev.yml up -- build --force-recreate +docker-compose -f docker-compose.dev.yml --build --force-recreate up ``` Build and run the Login UI: From 42f47df508312f4a28a3a0d4a71859d40c053ed4 Mon Sep 17 00:00:00 2001 From: Nikos Date: Fri, 5 Jan 2024 14:56:04 +0200 Subject: [PATCH 5/9] feat: add create-fga-model CLI command --- cmd/createFgaModel.go | 67 ++++++++++++++++++++++++++++ internal/authorization/interfaces.go | 2 + internal/tracing/noop.go | 27 ----------- 3 files changed, 69 insertions(+), 27 deletions(-) create mode 100644 cmd/createFgaModel.go delete mode 100644 internal/tracing/noop.go diff --git a/cmd/createFgaModel.go b/cmd/createFgaModel.go new file mode 100644 index 000000000..c6e474ed8 --- /dev/null +++ b/cmd/createFgaModel.go @@ -0,0 +1,67 @@ +/* +Copyright © 2024 NAME HERE +*/ +package cmd + +import ( + "context" + "fmt" + "net/url" + + authz "github.com/canonical/identity-platform-login-ui/internal/authorization" + logging "github.com/canonical/identity-platform-login-ui/internal/logging" + monitoring "github.com/canonical/identity-platform-login-ui/internal/monitoring" + fga "github.com/canonical/identity-platform-login-ui/internal/openfga" + tracing "github.com/canonical/identity-platform-login-ui/internal/tracing" + "github.com/spf13/cobra" +) + +// createFgaModelCmd represents the createFgaModel command +var createFgaModelCmd = &cobra.Command{ + Use: "create-fga-model", + Short: "Creates an openfga model", + Long: `Creates an openfga model`, + Run: func(cmd *cobra.Command, args []string) { + apiUrl, _ := cmd.Flags().GetString("fga-api-url") + apiToken, _ := cmd.Flags().GetString("fga-api-token") + storeId, _ := cmd.Flags().GetString("store-id") + createModel(apiUrl, apiToken, storeId) + }, +} + +func init() { + rootCmd.AddCommand(createFgaModelCmd) + + createFgaModelCmd.PersistentFlags().String("fga-api-url", "", "The openfga API URL") + createFgaModelCmd.PersistentFlags().String("fga-api-token", "", "The openfga API token") + createFgaModelCmd.PersistentFlags().String("store-id", "", "The openfga store to create the model in") + createFgaModelCmd.MarkPersistentFlagRequired("api-url") + createFgaModelCmd.MarkPersistentFlagRequired("api-token") + createFgaModelCmd.MarkPersistentFlagRequired("store-id") +} + +func createModel(apiUrl, apiToken, storeId string) { + logger := logging.NewNoopLogger() + tracer := tracing.NewNoopTracer() + monitor := monitoring.NewNoopMonitor("", logger) + scheme, host, err := parseURL(apiUrl) + if err != nil { + panic(err) + } + cfg := fga.NewConfig(scheme, host, storeId, apiToken, "", false, tracer, monitor, logger) + authzClient := fga.NewClient(cfg) + authorizer := authz.NewAuthorizer(authzClient, tracer, monitor, logger) + modelId, err := authorizer.CreateModel(context.Background()) + if err != nil { + panic(err) + } + fmt.Printf("Created model: %s\n", modelId) +} + +func parseURL(s string) (string, string, error) { + u, err := url.Parse(s) + if err != nil { + return "", "", err + } + return u.Scheme, u.Host, nil +} diff --git a/internal/authorization/interfaces.go b/internal/authorization/interfaces.go index ef67824da..c11576af5 100644 --- a/internal/authorization/interfaces.go +++ b/internal/authorization/interfaces.go @@ -11,6 +11,7 @@ type AuthorizerInterface interface { Check(context.Context, string, string, string) (bool, error) FilterObjects(context.Context, string, string, string, []string) ([]string, error) ValidateModel(context.Context) error + CreateModel(context.Context) (string, error) } type AuthzClientInterface interface { @@ -18,4 +19,5 @@ type AuthzClientInterface interface { Check(context.Context, string, string, string) (bool, error) ReadModel(context.Context) (*fga.AuthorizationModel, error) CompareModel(context.Context, fga.AuthorizationModel) (bool, error) + WriteModel(context.Context, []byte) (string, error) } diff --git a/internal/tracing/noop.go b/internal/tracing/noop.go deleted file mode 100644 index ebcc8e90e..000000000 --- a/internal/tracing/noop.go +++ /dev/null @@ -1,27 +0,0 @@ -package tracing - -import ( - "context" - - "github.com/canonical/identity-platform-login-ui/internal/logging" - "go.opentelemetry.io/otel/trace" - "go.opentelemetry.io/otel/trace/embedded" - "go.opentelemetry.io/otel/trace/noop" -) - -type NoopTracer struct { - embedded.Tracer - tracer trace.Tracer - - logger logging.LoggerInterface -} - -func NewNoopTracer(cfg *Config) *NoopTracer { - t := new(NoopTracer) - t.tracer = new(noop.Tracer) - return t -} - -func (t *NoopTracer) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { - return t.tracer.Start(ctx, spanName, opts...) -} From c595939e6ebffa562fa9597edfc9d677dda9280c Mon Sep 17 00:00:00 2001 From: Nikos Date: Fri, 5 Jan 2024 17:51:54 +0200 Subject: [PATCH 6/9] fix: update rockcraft.yaml --- rockcraft.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rockcraft.yaml b/rockcraft.yaml index 9a79b2f1d..8da153623 100644 --- a/rockcraft.yaml +++ b/rockcraft.yaml @@ -15,7 +15,7 @@ platforms: services: login-ui: override: replace - command: /usr/bin/identity-platform-login-ui + command: /usr/bin/identity-platform-login-ui serve startup: enabled parts: @@ -36,7 +36,7 @@ parts: - git override-build: | make npm-build build - install -D -m755 cmd/app ${CRAFT_PART_INSTALL}/opt/identity-platform-login-ui/bin/app + install -D -m755 app ${CRAFT_PART_INSTALL}/opt/identity-platform-login-ui/bin/app organize: opt/identity-platform-login-ui/bin/app: usr/bin/identity-platform-login-ui stage-packages: From 57b37f8b7102b4b62057f27c9648e6546e9a0e67 Mon Sep 17 00:00:00 2001 From: Nikos Date: Mon, 8 Jan 2024 14:17:46 +0200 Subject: [PATCH 7/9] fix: switch to zap nop logger --- internal/logging/noop.go | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/internal/logging/noop.go b/internal/logging/noop.go index d94be142a..b74451234 100644 --- a/internal/logging/noop.go +++ b/internal/logging/noop.go @@ -1,19 +1,9 @@ package logging -type NoopLogger struct { -} +import ( + "go.uber.org/zap" +) -func NewNoopLogger() *NoopLogger { - return new(NoopLogger) +func NewNoopLogger() *zap.SugaredLogger { + return zap.NewNop().Sugar() } - -func (l *NoopLogger) Errorf(string, ...interface{}) {} -func (l *NoopLogger) Infof(string, ...interface{}) {} -func (l *NoopLogger) Warnf(string, ...interface{}) {} -func (l *NoopLogger) Debugf(string, ...interface{}) {} -func (l *NoopLogger) Fatalf(string, ...interface{}) {} -func (l *NoopLogger) Error(...interface{}) {} -func (l *NoopLogger) Info(...interface{}) {} -func (l *NoopLogger) Warn(...interface{}) {} -func (l *NoopLogger) Debug(...interface{}) {} -func (l *NoopLogger) Fatal(...interface{}) {} From 462e2871be964b860aa9dc6e18fe395976f1db29 Mon Sep 17 00:00:00 2001 From: Nikos Date: Mon, 8 Jan 2024 14:24:59 +0200 Subject: [PATCH 8/9] refactor: remove CreateModel from authorizer --- Makefile | 2 +- cmd/createFgaModel.go | 5 ++--- internal/authorization/auth_model.go | 2 +- internal/authorization/authorization.go | 10 +--------- internal/authorization/interfaces.go | 2 -- 5 files changed, 5 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index e0b3de7e7..614efe4ed 100644 --- a/Makefile +++ b/Makefile @@ -46,5 +46,5 @@ npm-build: .PHONY: npm-build update-openfga-model: - @printf 'package authorization\n\n// Code generated by Makefile; DO NOT EDIT.\n\nvar authModel = `%s`\n' '$(shell fga model transform --file=./internal/authorization/schema.openfga | jq -c)' > ./internal/authorization/auth_model.go + @printf 'package authorization\n\n// Code generated by Makefile; DO NOT EDIT.\n\nvar AuthModel = `%s`\n' '$(shell fga model transform --file=./internal/authorization/schema.openfga | jq -c)' > ./internal/authorization/auth_model.go .PHONY: update-openfga-model diff --git a/cmd/createFgaModel.go b/cmd/createFgaModel.go index c6e474ed8..76fd3fcda 100644 --- a/cmd/createFgaModel.go +++ b/cmd/createFgaModel.go @@ -49,9 +49,8 @@ func createModel(apiUrl, apiToken, storeId string) { panic(err) } cfg := fga.NewConfig(scheme, host, storeId, apiToken, "", false, tracer, monitor, logger) - authzClient := fga.NewClient(cfg) - authorizer := authz.NewAuthorizer(authzClient, tracer, monitor, logger) - modelId, err := authorizer.CreateModel(context.Background()) + fgaClient := fga.NewClient(cfg) + modelId, err := fgaClient.WriteModel(context.Background(), []byte(authz.AuthModel)) if err != nil { panic(err) } diff --git a/internal/authorization/auth_model.go b/internal/authorization/auth_model.go index 18a112909..6269a0426 100644 --- a/internal/authorization/auth_model.go +++ b/internal/authorization/auth_model.go @@ -2,4 +2,4 @@ package authorization // Code generated by Makefile; DO NOT EDIT. -var authModel = `{"schema_version":"1.1","type_definitions":[{"type":"user"},{"type":"app"},{"metadata":{"relations":{"member":{"directly_related_user_types":[{"type":"user"},{"relation":"member","type":"group"}]}}},"relations":{"member":{"this":{}}},"type":"group"},{"metadata":{"relations":{"member":{"directly_related_user_types":[{"type":"app"},{"relation":"member","type":"app_group"}]}}},"relations":{"member":{"this":{}}},"type":"app_group"},{"metadata":{"relations":{"allowed_access":{"directly_related_user_types":[{"type":"app"},{"relation":"member","type":"app_group"}]},"member":{"directly_related_user_types":[{"type":"user"}]}}},"relations":{"allowed_access":{"this":{}},"member":{"this":{}}},"type":"provider"}]}` +var AuthModel = `{"schema_version":"1.1","type_definitions":[{"type":"user"},{"type":"app"},{"metadata":{"relations":{"member":{"directly_related_user_types":[{"type":"user"},{"relation":"member","type":"group"}]}}},"relations":{"member":{"this":{}}},"type":"group"},{"metadata":{"relations":{"member":{"directly_related_user_types":[{"type":"app"},{"relation":"member","type":"app_group"}]}}},"relations":{"member":{"this":{}}},"type":"app_group"},{"metadata":{"relations":{"allowed_access":{"directly_related_user_types":[{"type":"app"},{"relation":"member","type":"app_group"}]},"member":{"directly_related_user_types":[{"type":"user"}]}}},"relations":{"allowed_access":{"this":{}},"member":{"this":{}}},"type":"provider"}]}` diff --git a/internal/authorization/authorization.go b/internal/authorization/authorization.go index 5635005b0..283305c29 100644 --- a/internal/authorization/authorization.go +++ b/internal/authorization/authorization.go @@ -53,20 +53,12 @@ func (a *Authorizer) FilterObjects(ctx context.Context, user string, relation st return ret, nil } -func (a *Authorizer) CreateModel(ctx context.Context) (string, error) { - ctx, span := a.tracer.Start(ctx, "authorization.Authorizer.CreateModel") - defer span.End() - - modelId, err := a.Client.WriteModel(ctx, []byte(authModel)) - return modelId, err -} - func (a *Authorizer) ValidateModel(ctx context.Context) error { ctx, span := a.tracer.Start(ctx, "authorization.Authorizer.ValidateModel") defer span.End() var builtinAuthorizationModel fga.AuthorizationModel - err := json.Unmarshal([]byte(authModel), &builtinAuthorizationModel) + err := json.Unmarshal([]byte(AuthModel), &builtinAuthorizationModel) if err != nil { return err } diff --git a/internal/authorization/interfaces.go b/internal/authorization/interfaces.go index c11576af5..ef67824da 100644 --- a/internal/authorization/interfaces.go +++ b/internal/authorization/interfaces.go @@ -11,7 +11,6 @@ type AuthorizerInterface interface { Check(context.Context, string, string, string) (bool, error) FilterObjects(context.Context, string, string, string, []string) ([]string, error) ValidateModel(context.Context) error - CreateModel(context.Context) (string, error) } type AuthzClientInterface interface { @@ -19,5 +18,4 @@ type AuthzClientInterface interface { Check(context.Context, string, string, string) (bool, error) ReadModel(context.Context) (*fga.AuthorizationModel, error) CompareModel(context.Context, fga.AuthorizationModel) (bool, error) - WriteModel(context.Context, []byte) (string, error) } From c0c9365dbab8d683cf702e05a12f4ca6d8e9b211 Mon Sep 17 00:00:00 2001 From: Nikos Date: Tue, 9 Jan 2024 16:15:47 +0200 Subject: [PATCH 9/9] chore: update readme --- README.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 817344d91..9178d3083 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ At the moment the application is sourcing the following from the environment: ## Container + To build the UI oci image, you will need [rockcraft](https://canonical-rockcraft.readthedocs-hosted.com). To install rockcraft run: @@ -106,7 +107,7 @@ export PORT=4455 export TRACING_ENABLED=false export LOG_LEVEL=debug export AUTHORIZATION_ENABLED=false -./cmd/app +./app serve ``` To test the authorizatoin code flow you can use the Ory Hydra CLI: @@ -130,3 +131,34 @@ hydra perform authorization-code \ --client-secret `echo "$code_client" | yq .client_secret` \ --scope openid,profile,email,offline_access ``` + +## OpenFGA Model Creation + +The login UI relies to [OpenFGA](https://github.com/openfga/openfga/) for authorization decisions. +After you deploy the OpenFGA server, you need to create the OpenFGA store and model: + +```console +./login-ui-binary create-fga-model --fga-api-token $OPENFGA_API_TOKEN --fga-api-url $OPENFGA_API_URL --store-id $STORE_ID +``` + +To try it locally you can deploy OpenFGA using docker-compose: +```console +docker-compose -f docker-compose.dev.yml --build --force-recreate up +``` + +And run with the store: +```console +make build +./app create-fga-model --fga-api-token 42 --fga-api-url http://localhost:8080 --store-id 01GP1254CHWJC1MNGVB0WDG1T0 + +export KRATOS_PUBLIC_URL=http://localhost:4433 +export HYDRA_ADMIN_URL=http://localhost:4445 +export BASE_URL=http://localhost:4455 +export OPENFGA_API_SCHEME=http +export OPENFGA_API_HOST=localhost:8080 +export OPENFGA_STORE_ID=01GP1254CHWJC1MNGVB0WDG1T0 +export OPENFGA_API_TOKEN=42 +export OPENFGA_AUTHORIZATION_MODEL_ID=01HGG9ZQ9PP3P6QHW93QBM55KM +export AUTHORIZATION_ENABLED=false +./app serve +```