diff --git a/cmd/jimmctl/cmd/relation_test.go b/cmd/jimmctl/cmd/relation_test.go index b7d51183a..ac0dfd45c 100644 --- a/cmd/jimmctl/cmd/relation_test.go +++ b/cmd/jimmctl/cmd/relation_test.go @@ -339,7 +339,7 @@ func initializeEnvironment(c *gc.C, ctx context.Context, db *db.Database, u dbmo } func (s *relationSuite) TestListRelations(c *gc.C) { - env := initializeEnvironment(c, context.Background(), &s.JIMM.Database, *s.AdminUser) + env := initializeEnvironment(c, context.Background(), s.JIMM.Database, *s.AdminUser) bClient := s.SetupCLIAccess(c, "alice") // alice is superuser relations := []apiparams.RelationshipTuple{{ @@ -420,7 +420,7 @@ func (s *relationSuite) TestListRelations(c *gc.C) { } func (s *relationSuite) TestListRelationsWithError(c *gc.C) { - env := initializeEnvironment(c, context.Background(), &s.JIMM.Database, *s.AdminUser) + env := initializeEnvironment(c, context.Background(), s.JIMM.Database, *s.AdminUser) // alice is superuser bClient := s.SetupCLIAccess(c, "alice") diff --git a/cmd/jimmsrv/main.go b/cmd/jimmsrv/main.go index 30beec722..402d0d064 100644 --- a/cmd/jimmsrv/main.go +++ b/cmd/jimmsrv/main.go @@ -183,36 +183,12 @@ func start(ctx context.Context, s *service.Service) error { CorsAllowedOrigins: corsAllowedOrigins, LogSQL: logSQL, LogLevel: logLevel, - }) + IsLeader: os.Getenv("JIMM_IS_LEADER") != "", + }, s) if err != nil { return err } - isLeader := os.Getenv("JIMM_IS_LEADER") != "" - if isLeader { - s.Go(func() error { return jimmsvc.WatchControllers(ctx) }) // Deletes dead/dying models, updates model config. - } - s.Go(func() error { return jimmsvc.WatchModelSummaries(ctx) }) - - if isLeader { - zapctx.Info(ctx, "attempting to start JWKS rotator and generate OAuth secret key") - s.Go(func() error { - if err := jimmsvc.StartJWKSRotator(ctx, time.NewTicker(time.Hour).C, time.Now().UTC().AddDate(0, 3, 0)); err != nil { - zapctx.Error(ctx, "failed to start JWKS rotator", zap.Error(err)) - return err - } - return nil - }) - s.Go(func() error { - return jimmsvc.OpenFGACleanup(ctx, time.NewTicker(6*time.Hour).C) - }) - } - - if isLeader { - // No need for s.Go() since this routine doesn't return an error. - go jimmsvc.MonitorResources(ctx) - } - httpsrv := &http.Server{ Addr: addr, Handler: jimmsvc, diff --git a/cmd/jimmsrv/service/service.go b/cmd/jimmsrv/service/service.go index 232f1a980..dc2bfe11d 100644 --- a/cmd/jimmsrv/service/service.go +++ b/cmd/jimmsrv/service/service.go @@ -13,6 +13,7 @@ import ( "time" "github.com/antonlindstrom/pgstore" + service "github.com/canonical/go-service" cofga "github.com/canonical/ofga" "github.com/go-chi/chi/v5" chimiddleware "github.com/go-chi/chi/v5/middleware" @@ -27,12 +28,12 @@ import ( "gorm.io/gorm" "github.com/canonical/jimm/v3/internal/auth" + "github.com/canonical/jimm/v3/internal/db" "github.com/canonical/jimm/v3/internal/dbmodel" "github.com/canonical/jimm/v3/internal/discharger" "github.com/canonical/jimm/v3/internal/errors" "github.com/canonical/jimm/v3/internal/jimm" jimmcreds "github.com/canonical/jimm/v3/internal/jimm/credentials" - "github.com/canonical/jimm/v3/internal/jimm/role" "github.com/canonical/jimm/v3/internal/jimmhttp" "github.com/canonical/jimm/v3/internal/jimmhttp/rebac_admin" "github.com/canonical/jimm/v3/internal/jimmjwx" @@ -100,6 +101,9 @@ type Params struct { // is not set a random UUID will be generated. ControllerUUID string + // IsLeader indicates that this is the JIMM leader unit. + IsLeader bool + // DSN is the data source name that the JIMM service will use to // connect to its database. If this is empty an in-memory database // will be used. @@ -194,14 +198,14 @@ type Params struct { // A Service is the implementation of a JIMM server. type Service struct { - jimm jimm.JIMM + jimm *jimm.JIMM mux *chi.Mux cleanups []func() error } func (s *Service) JIMM() *jimm.JIMM { - return &s.jimm + return s.jimm } // ServeHTTP implements http.Handler. @@ -213,6 +217,10 @@ func (s *Service) ServeHTTP(w http.ResponseWriter, req *http.Request) { // monitoring all changes to models. WatchControllers finishes when the // given context is canceled, or there is a fatal error watching models. func (s *Service) WatchControllers(ctx context.Context) error { + if s.jimm == nil { + zapctx.Error(ctx, "jimm not created") + return errors.E("jimm not created") + } w := jimm.Watcher{ Database: s.jimm.Database, Dialer: s.jimm.Dialer, @@ -225,6 +233,10 @@ func (s *Service) WatchControllers(ctx context.Context) error { // the given context is canceled, or there is a fatal error watching model // summaries. func (s *Service) WatchModelSummaries(ctx context.Context) error { + if s.jimm == nil { + zapctx.Error(ctx, "jimm not created") + return errors.E("jimm not created") + } w := jimm.Watcher{ Database: s.jimm.Database, Dialer: s.jimm.Dialer, @@ -235,6 +247,10 @@ func (s *Service) WatchModelSummaries(ctx context.Context) error { // StartJWKSRotator see internal/jimmjwx/jwks.go for details. func (s *Service) StartJWKSRotator(ctx context.Context, checkRotateRequired <-chan time.Time, initialRotateRequiredTime time.Time) error { + if s.jimm == nil { + zapctx.Error(ctx, "jimm not created") + return errors.E("jimm not created") + } if s.jimm.JWKService == nil { zapctx.Warn(ctx, "not starting JWKS rotation") return nil @@ -244,6 +260,10 @@ func (s *Service) StartJWKSRotator(ctx context.Context, checkRotateRequired <-ch // MonitorResources periodically updates metrics. func (s *Service) MonitorResources(ctx context.Context) { + if s.jimm == nil { + zapctx.Error(ctx, "jimm not created") + return + } s.jimm.UpdateMetrics(ctx) ticker := time.NewTicker(5 * time.Minute) for { @@ -258,6 +278,10 @@ func (s *Service) MonitorResources(ctx context.Context) { // OpenFGACleanup starts a goroutine that cleans up any orphaned tuples from OpenFGA. func (s *Service) OpenFGACleanup(ctx context.Context, trigger <-chan time.Time) error { + if s.jimm == nil { + zapctx.Error(ctx, "jimm not created") + return errors.E("jimm not created") + } for { select { case <-trigger: @@ -289,7 +313,7 @@ func (s *Service) AddCleanup(f func() error) { } // NewService creates a new Service using the given params. -func NewService(ctx context.Context, p Params) (*Service, error) { +func NewService(ctx context.Context, p Params, svc *service.Service) (*Service, error) { const op = errors.Op("NewService") s := new(Service) @@ -298,57 +322,42 @@ func NewService(ctx context.Context, p Params) (*Service, error) { s.mux.Use(chimiddleware.RequestLogger(&logger.HTTPLogFormatter{})) s.mux.Use(middleware.MeasureHTTPResponseTime) + jimmParameters := jimm.Parameters{ + UUID: p.ControllerUUID, + Pubsub: &pubsub.Hub{MaxConcurrency: 50}, + } // Setup all dependency services - - if p.ControllerUUID == "" { - controllerUUID, err := uuid.NewRandom() - if err != nil { - return nil, errors.E(op, err) - } - p.ControllerUUID = controllerUUID.String() + if jimmParameters.UUID == "" { + jimmParameters.UUID = uuid.NewString() } - s.jimm.UUID = p.ControllerUUID - s.jimm.Pubsub = &pubsub.Hub{MaxConcurrency: 50} if p.DSN == "" { return nil, errors.E(op, "missing DSN") } - var err error - s.jimm.Database.DB, err = openDB(ctx, p.DSN, p.LogSQL) + database, err := openDB(ctx, p.DSN, p.LogSQL) if err != nil { return nil, errors.E(op, err) } - if err := s.jimm.Database.Migrate(ctx, false); err != nil { - return nil, errors.E(op, err) - } - - if p.AuditLogRetentionPeriodInDays != "" { - period, err := strconv.Atoi(p.AuditLogRetentionPeriodInDays) - if err != nil { - return nil, errors.E(op, "failed to parse audit log retention period") - } - if period < 0 { - return nil, errors.E(op, "retention period cannot be less than 0") - } - if period != 0 { - jimm.NewAuditLogCleanupService(s.jimm.Database, period).Start(ctx) - } + jimmParameters.Database = &db.Database{ + DB: database, } openFGAclient, err := newOpenFGAClient(ctx, p.OpenFGAParams) if err != nil { return nil, errors.E(op, err) } - s.jimm.OpenFGAClient = openFGAclient + jimmParameters.OpenFGAClient = openFGAclient if err := ensureControllerAdministrators(ctx, openFGAclient, p.ControllerUUID, p.ControllerAdmins); err != nil { return nil, errors.E(op, err, "failed to ensure controller admins") } - if err := s.setupCredentialStore(ctx, p); err != nil { + credentialStore, err := s.setupCredentialStore(ctx, p, jimmParameters) + if err != nil { return nil, errors.E(op, err) } + jimmParameters.CredentialStore = credentialStore - sessionStore, err := s.setupSessionStore(ctx, p.CookieSessionKey) + sessionStore, err := s.setupSessionStore(ctx, p.CookieSessionKey, jimmParameters) if err != nil { return nil, errors.E(op, err) } @@ -373,12 +382,12 @@ func NewService(ctx context.Context, p Params) (*Service, error) { SessionCookieMaxAge: p.OAuthAuthenticatorParams.SessionCookieMaxAge, JWTSessionKey: p.OAuthAuthenticatorParams.JWTSessionKey, SecureCookies: p.OAuthAuthenticatorParams.SecureSessionCookies, - Store: &s.jimm.Database, + Store: jimmParameters.Database, SessionStore: sessionStore, RedirectURL: redirectUrl, }, ) - s.jimm.OAuthAuthenticator = authSvc + jimmParameters.OAuthAuthenticator = authSvc if err != nil { zapctx.Error(ctx, "failed to setup authentication service", zap.Error(err)) return nil, errors.E(op, err, "failed to setup authentication service") @@ -388,32 +397,71 @@ func NewService(ctx context.Context, p Params) (*Service, error) { p.JWTExpiryDuration = 24 * time.Hour } - s.jimm.JWKService = jimmjwx.NewJWKSService(s.jimm.CredentialStore) - s.jimm.JWTService = jimmjwx.NewJWTService(jimmjwx.JWTServiceParams{ + jimmParameters.JWKService = jimmjwx.NewJWKSService(jimmParameters.CredentialStore) + jimmParameters.JWTService = jimmjwx.NewJWTService(jimmjwx.JWTServiceParams{ Host: p.PublicDNSName, - Store: s.jimm.CredentialStore, + Store: jimmParameters.CredentialStore, Expiry: p.JWTExpiryDuration, }) - s.jimm.Dialer = &jujuclient.Dialer{ - ControllerCredentialsStore: s.jimm.CredentialStore, - JWTService: s.jimm.JWTService, - } - - roleManager, err := role.NewRoleManager(&s.jimm.Database, s.jimm.OpenFGAClient) - if err != nil { - return nil, errors.E(op, err, "failed to create RoleManager") + jimmParameters.Dialer = &jujuclient.Dialer{ + ControllerCredentialsStore: jimmParameters.CredentialStore, + JWTService: jimmParameters.JWTService, } - s.jimm.RoleManager = roleManager if !p.DisableConnectionCache { - s.jimm.Dialer = jimm.CacheDialer(s.jimm.Dialer) + jimmParameters.Dialer = jimm.CacheDialer(jimmParameters.Dialer) } if _, err := url.Parse(p.DashboardFinalRedirectURL); err != nil { return nil, errors.E(op, err, "failed to parse final redirect url for the dashboard") } - rebacBackend, err := rebac_admin.SetupBackend(ctx, &s.jimm) + // instantiate jimm + s.jimm, err = jimm.New(jimmParameters) + if err != nil { + return nil, errors.E(op, err) + } + + var auditLogCleanupPeriod int + if p.AuditLogRetentionPeriodInDays != "" { + auditLogCleanupPeriod, err = strconv.Atoi(p.AuditLogRetentionPeriodInDays) + if err != nil { + return nil, errors.E(op, "failed to parse audit log retention period") + } + if auditLogCleanupPeriod < 0 { + return nil, errors.E(op, "retention period cannot be less than 0") + } + } + + if p.IsLeader { + if auditLogCleanupPeriod != 0 { + svc.Go(func() error { + jimm.NewAuditLogCleanupService(jimmParameters.Database, auditLogCleanupPeriod).Start(ctx) + return nil + }) + } + + svc.Go(func() error { + return s.WatchControllers(ctx) + }) + svc.Go(func() error { + if err := s.StartJWKSRotator(ctx, time.NewTicker(time.Hour).C, time.Now().UTC().AddDate(0, 3, 0)); err != nil { + zapctx.Error(ctx, "failed to start JWKS rotator", zap.Error(err)) + return err + } + return nil + }) + svc.Go(func() error { + return s.OpenFGACleanup(ctx, time.NewTicker(6*time.Hour).C) + }) + svc.Go(func() error { + s.MonitorResources(ctx) + return nil + }) + } + svc.Go(func() error { return s.WatchModelSummaries(ctx) }) + + rebacBackend, err := rebac_admin.SetupBackend(ctx, s.jimm) if err != nil { return nil, errors.E(op, err) } @@ -433,7 +481,7 @@ func NewService(ctx context.Context, p Params) (*Service, error) { s.mux.Mount("/metrics", promhttp.Handler()) - s.mux.Mount("/rebac", middleware.AuthenticateRebac("/rebac", rebacBackend.Handler(""), &s.jimm)) + s.mux.Mount("/rebac", middleware.AuthenticateRebac("/rebac", rebacBackend.Handler(""), s.jimm)) mountHandler( "/debug", @@ -479,11 +527,11 @@ func NewService(ctx context.Context, p Params) (*Service, error) { // Websockets require extra care when cookies are used for authentication // to avoid CSRF attacks. https://portswigger.net/web-security/websockets/cross-site-websocket-hijacking websocketCors := middleware.NewWebsocketCors(p.CorsAllowedOrigins) - s.mux.Handle("/api", websocketCors.Handler(jujuapi.APIHandler(ctx, &s.jimm, params))) - s.mux.Handle("/model/*", websocketCors.Handler(http.StripPrefix("/model", jujuapi.ModelHandler(ctx, &s.jimm, params)))) + s.mux.Handle("/api", websocketCors.Handler(jujuapi.APIHandler(ctx, s.jimm, params))) + s.mux.Handle("/model/*", websocketCors.Handler(http.StripPrefix("/model", jujuapi.ModelHandler(ctx, s.jimm, params)))) mountHandler( "/model/{uuid}/{type:charms|applications}", - jimmhttp.NewHTTPProxyHandler(&s.jimm), + jimmhttp.NewHTTPProxyHandler(s.jimm), ) return s, nil @@ -499,21 +547,21 @@ func (s *Service) setupDischarger(p Params) (*discharger.MacaroonDischarger, err MacaroonExpiryDuration: p.MacaroonExpiryDuration, ControllerUUID: p.ControllerUUID, } - MacaroonDischarger, err := discharger.NewMacaroonDischarger(cfg, &s.jimm.Database, s.jimm.OpenFGAClient) + MacaroonDischarger, err := discharger.NewMacaroonDischarger(cfg, s.jimm.Database, s.jimm.OpenFGAClient) if err != nil { return nil, errors.E(err) } return MacaroonDischarger, nil } -func (s *Service) setupSessionStore(ctx context.Context, sessionSecret []byte) (*pgstore.PGStore, error) { +func (s *Service) setupSessionStore(ctx context.Context, sessionSecret []byte, jimmParameters jimm.Parameters) (*pgstore.PGStore, error) { const op = errors.Op("setupSessionStore") - if s.jimm.CredentialStore == nil { + if jimmParameters.CredentialStore == nil { return nil, errors.E(op, "credential store is not configured") } - sqlDb, err := s.jimm.Database.DB.DB() + sqlDb, err := jimmParameters.Database.DB.DB() if err != nil { return nil, errors.E(op, err) } @@ -554,27 +602,25 @@ func openDB(ctx context.Context, dsn string, logSQL bool) (*gorm.DB, error) { }) } -func (s *Service) setupCredentialStore(ctx context.Context, p Params) error { +func (s *Service) setupCredentialStore(ctx context.Context, p Params, jimmParameters jimm.Parameters) (jimmcreds.CredentialStore, error) { const op = errors.Op("newSecretStore") // Only enable Postgres storage for secrets if explicitly enabled. if p.InsecureSecretStorage { zapctx.Warn(ctx, "using plaintext postgres for secret storage") - s.jimm.CredentialStore = &s.jimm.Database - return nil + return jimmParameters.Database, nil } vs, err := newVaultStore(ctx, p) if err != nil { zapctx.Error(ctx, "Vault Store error", zap.Error(err)) - return errors.E(op, err) + return nil, errors.E(op, err) } if vs != nil { - s.jimm.CredentialStore = vs - return nil + return vs, nil } - return errors.E(op, "jimm cannot start without a credential store") + return nil, errors.E(op, "jimm cannot start without a credential store") } func newVaultStore(ctx context.Context, p Params) (jimmcreds.CredentialStore, error) { diff --git a/cmd/jimmsrv/service/service_test.go b/cmd/jimmsrv/service/service_test.go index 5498033b7..6dadc0269 100644 --- a/cmd/jimmsrv/service/service_test.go +++ b/cmd/jimmsrv/service/service_test.go @@ -10,9 +10,11 @@ import ( "net/http/httptest" "net/url" "os" + "syscall" "testing" "time" + gosvc "github.com/canonical/go-service" cofga "github.com/canonical/ofga" "github.com/coreos/go-oidc/v3/oidc" qt "github.com/frankban/quicktest" @@ -38,10 +40,10 @@ func TestMain(m *testing.M) { os.Exit(code) } -// newTestJimmParams returns a set of JIMM params with sensible defaults +// newTestServiceParameters returns a set of JIMM params with sensible defaults // for tests. A test can override any parameter that it needs. -// Note that newTestJimmParams will create an empty test database. -func newTestJimmParams(t jimmtest.Tester) jimmsvc.Params { +// Note that newTestServiceParameters will create an empty test database. +func newTestServiceParameters(t jimmtest.Tester) jimmsvc.Params { return jimmsvc.Params{ DSN: jimmtest.CreateEmptyDatabase(t), ControllerUUID: "6acf4fd8-32d6-49ea-b4eb-dcb9d1590c11", @@ -61,13 +63,16 @@ func newTestJimmParams(t jimmtest.Tester) jimmsvc.Params { func TestDefaultService(t *testing.T) { c := qt.New(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) _, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) p.InsecureSecretStorage = true - svc, err := jimmsvc.NewService(context.Background(), p) + svc, err := jimmsvc.NewService(ctx, p, s) c.Assert(err, qt.IsNil) defer svc.Cleanup() rr := httptest.NewRecorder() @@ -81,25 +86,31 @@ func TestDefaultService(t *testing.T) { func TestServiceDoesNotStartWithoutCredentialStore(t *testing.T) { c := qt.New(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) _, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) - _, err = jimmsvc.NewService(context.Background(), p) + _, err = jimmsvc.NewService(context.Background(), p, s) c.Assert(err, qt.ErrorMatches, "jimm cannot start without a credential store") } func TestAuthenticator(t *testing.T) { c := qt.New(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) _, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.InsecureSecretStorage = true p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) - svc, err := jimmsvc.NewService(context.Background(), p) + svc, err := jimmsvc.NewService(context.Background(), p, s) c.Assert(err, qt.IsNil) defer svc.Cleanup() @@ -149,19 +160,21 @@ const testVaultEnv = `clouds: func TestVault(t *testing.T) { c := qt.New(t) - ctx := context.Background() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) ofgaClient, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) vaultClient, _, roleID, roleSecretID, _ := jimmtest.VaultClient(c) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.VaultAddress = "http://localhost:8200" p.VaultPath = "/jimm-kv/" p.VaultRoleID = roleID p.VaultRoleSecretID = roleSecretID p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) - svc, err := jimmsvc.NewService(ctx, p) + svc, err := jimmsvc.NewService(ctx, p, s) c.Assert(err, qt.IsNil) defer svc.Cleanup() @@ -212,30 +225,35 @@ func TestVault(t *testing.T) { func TestPostgresSecretStore(t *testing.T) { c := qt.New(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) _, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.InsecureSecretStorage = true p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) - svc, err := jimmsvc.NewService(context.Background(), p) + svc, err := jimmsvc.NewService(context.Background(), p, s) c.Assert(err, qt.IsNil) defer svc.Cleanup() } func TestOpenFGA(t *testing.T) { c := qt.New(t) - ctx := context.Background() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) _, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.InsecureSecretStorage = true p.ControllerAdmins = []string{"alice", "eve"} p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) - svc, err := jimmsvc.NewService(ctx, p) + svc, err := jimmsvc.NewService(ctx, p, s) c.Assert(err, qt.IsNil) defer svc.Cleanup() @@ -275,14 +293,17 @@ func TestOpenFGA(t *testing.T) { func TestPublicKey(t *testing.T) { c := qt.New(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) _, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) p.InsecureSecretStorage = true - svc, err := jimmsvc.NewService(context.Background(), p) + svc, err := jimmsvc.NewService(context.Background(), p, s) c.Assert(err, qt.IsNil) defer svc.Cleanup() @@ -299,15 +320,18 @@ func TestPublicKey(t *testing.T) { func TestRebacAdminApi(t *testing.T) { c := qt.New(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) _, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.InsecureSecretStorage = true p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) - svc, err := jimmsvc.NewService(context.Background(), p) + svc, err := jimmsvc.NewService(context.Background(), p, s) c.Assert(err, qt.IsNil) defer svc.Cleanup() @@ -326,6 +350,8 @@ func TestRebacAdminApi(t *testing.T) { func TestThirdPartyCaveatDischarge(t *testing.T) { c := qt.New(t) + ctx := context.Background() + offer := dbmodel.ApplicationOffer{ UUID: "7e4e7ffb-5116-4544-a400-f584d08c410e", Name: "test-application-offer", @@ -333,8 +359,6 @@ func TestThirdPartyCaveatDischarge(t *testing.T) { user, err := dbmodel.NewIdentity("alice@canonical.com") c.Assert(err, qt.IsNil) - ctx := context.Background() - tests := []struct { about string setup func(c *qt.C, ofgaClient *openfga.OFGAClient, user *dbmodel.Identity) @@ -379,13 +403,17 @@ func TestThirdPartyCaveatDischarge(t *testing.T) { }} for _, test := range tests { c.Run(test.about, func(c *qt.C) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) + ofgaClient, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) p.InsecureSecretStorage = true - svc, err := jimmsvc.NewService(context.Background(), p) + svc, err := jimmsvc.NewService(context.Background(), p, s) c.Assert(err, qt.IsNil) defer svc.Cleanup() @@ -446,15 +474,18 @@ func TestThirdPartyCaveatDischarge(t *testing.T) { func TestDisableOAuthEndpointsWhenDashboardRedirectURLNotSet(t *testing.T) { c := qt.New(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) _, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.DashboardFinalRedirectURL = "" p.InsecureSecretStorage = true p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) - svc, err := jimmsvc.NewService(context.Background(), p) + svc, err := jimmsvc.NewService(context.Background(), p, s) c.Assert(err, qt.IsNil) defer svc.Cleanup() @@ -469,16 +500,19 @@ func TestDisableOAuthEndpointsWhenDashboardRedirectURLNotSet(t *testing.T) { func TestEnableOAuthEndpointsWhenDashboardRedirectURLSet(t *testing.T) { c := qt.New(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) _, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.DashboardFinalRedirectURL = "some-redirect-url" p.InsecureSecretStorage = true p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) - svc, err := jimmsvc.NewService(context.Background(), p) + svc, err := jimmsvc.NewService(context.Background(), p, s) c.Assert(err, qt.IsNil) defer svc.Cleanup() @@ -518,14 +552,17 @@ func TestCleanup(t *testing.T) { func TestCleanupDoesNotPanic_SessionStoreRelatedCleanups(t *testing.T) { c := qt.New(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) _, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) p.InsecureSecretStorage = true - svc, err := jimmsvc.NewService(context.Background(), p) + svc, err := jimmsvc.NewService(context.Background(), p, s) c.Assert(err, qt.IsNil) // Make sure `cleanups` is not empty. @@ -536,16 +573,19 @@ func TestCleanupDoesNotPanic_SessionStoreRelatedCleanups(t *testing.T) { func TestCORS(t *testing.T) { c := qt.New(t) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx, s := gosvc.NewService(ctx, os.Interrupt, syscall.SIGTERM) _, _, cofgaParams, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - p := newTestJimmParams(c) + p := newTestServiceParameters(c) p.OpenFGAParams = cofgaParamsToJIMMOpenFGAParams(*cofgaParams) allowedOrigin := "http://my-referrer.com" p.CorsAllowedOrigins = []string{allowedOrigin} p.InsecureSecretStorage = true - svc, err := jimmsvc.NewService(context.Background(), p) + svc, err := jimmsvc.NewService(context.Background(), p, s) c.Assert(err, qt.IsNil) defer svc.Cleanup() diff --git a/internal/db/cloud_test.go b/internal/db/cloud_test.go index 56ba0265b..5f935d869 100644 --- a/internal/db/cloud_test.go +++ b/internal/db/cloud_test.go @@ -244,7 +244,7 @@ controllers: region: test-region priority: 1 `) - env.PopulateDB(c, *s.Database) + env.PopulateDB(c, s.Database) cr, err := s.Database.FindRegion(ctx, "testp", "test-region") c.Assert(err, qt.IsNil) @@ -363,7 +363,7 @@ controllers: region: test-region-2 priority: 1 `) - env.PopulateDB(c, *s.Database) + env.PopulateDB(c, s.Database) cl := dbmodel.Cloud{ Name: "test-cloud-1", diff --git a/internal/db/cloudcredential_test.go b/internal/db/cloudcredential_test.go index b0d023619..ae1d541a1 100644 --- a/internal/db/cloudcredential_test.go +++ b/internal/db/cloudcredential_test.go @@ -278,7 +278,7 @@ func (s *dbSuite) TestForEachCloudCredential(c *qt.C) { env := jimmtest.ParseEnvironment(c, forEachCloudCredentialEnv) err := s.Database.Migrate(ctx, false) c.Assert(err, qt.IsNil) - env.PopulateDB(c, *s.Database) + env.PopulateDB(c, s.Database) for _, test := range forEachCloudCredentialTests { c.Run(test.name, func(c *qt.C) { diff --git a/internal/db/controller_test.go b/internal/db/controller_test.go index 7241f4b3f..2f4797da5 100644 --- a/internal/db/controller_test.go +++ b/internal/db/controller_test.go @@ -138,7 +138,7 @@ func (s *dbSuite) TestForEachController(c *qt.C) { c.Assert(err, qt.Equals, nil) env := jimmtest.ParseEnvironment(c, testForEachControllerEnv) - env.PopulateDB(c, *s.Database) + env.PopulateDB(c, s.Database) testError := errors.E("test error") err = s.Database.ForEachController(ctx, func(controller *dbmodel.Controller) error { @@ -321,9 +321,9 @@ func (s *dbSuite) TestForEachControllerModel(c *qt.C) { c.Assert(err, qt.Equals, nil) env := jimmtest.ParseEnvironment(c, testForEachControllerModelEnv) - env.PopulateDB(c, *s.Database) + env.PopulateDB(c, s.Database) - ctl := env.Controller("test").DBObject(c, *s.Database) + ctl := env.Controller("test").DBObject(c, s.Database) testError := errors.E("test error") err = s.Database.ForEachControllerModel(ctx, &ctl, func(_ *dbmodel.Model) error { return testError diff --git a/internal/db/identitymodeldefaults_test.go b/internal/db/identitymodeldefaults_test.go index 654690ff4..b92712b5a 100644 --- a/internal/db/identitymodeldefaults_test.go +++ b/internal/db/identitymodeldefaults_test.go @@ -23,6 +23,9 @@ func TestSetIdentityModelDefaults(t *testing.T) { ctx := context.Background() now := time.Now() + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + type testConfig struct { identity *dbmodel.Identity defaults map[string]interface{} @@ -135,12 +138,12 @@ func TestSetIdentityModelDefaults(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - j := &jimm.JIMM{ - Database: db.Database{ + j, err := jimm.New(jimm.Parameters{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - err := j.Database.Migrate(ctx, true) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.Equals, nil) testConfig := test.setup(c, j) diff --git a/internal/db/model_test.go b/internal/db/model_test.go index cc48fa4bb..cef4c0a68 100644 --- a/internal/db/model_test.go +++ b/internal/db/model_test.go @@ -533,7 +533,7 @@ func (s *dbSuite) TestForEachModel(c *qt.C) { c.Assert(err, qt.Equals, nil) env := jimmtest.ParseEnvironment(c, testForEachModelEnv) - env.PopulateDB(c, *s.Database) + env.PopulateDB(c, s.Database) testError := errors.E("test error") err = s.Database.ForEachModel(ctx, func(m *dbmodel.Model) error { @@ -619,7 +619,7 @@ func (s *dbSuite) TestGetModelsByUUID(c *qt.C) { c.Assert(err, qt.Equals, nil) env := jimmtest.ParseEnvironment(c, testGetModelsByUUIDEnv) - env.PopulateDB(c, *s.Database) + env.PopulateDB(c, s.Database) modelUUIDs := []string{ "00000002-0000-0000-0000-000000000001", @@ -782,9 +782,9 @@ func (s *dbSuite) TestCountModelsByController(c *qt.C) { c.Assert(err, qt.Equals, nil) env := jimmtest.ParseEnvironment(c, testCountModelsByControllerEnv) - env.PopulateDB(c, *s.Database) + env.PopulateDB(c, s.Database) c.Assert(len(env.Controllers), qt.Equals, 1) - count, err := s.Database.CountModelsByController(context.Background(), env.Controllers[0].DBObject(c, *s.Database)) + count, err := s.Database.CountModelsByController(context.Background(), env.Controllers[0].DBObject(c, s.Database)) c.Assert(err, qt.IsNil) c.Assert(count, qt.Equals, 3) } diff --git a/internal/jimm/access.go b/internal/jimm/access.go index 49887bcf7..68be24b03 100644 --- a/internal/jimm/access.go +++ b/internal/jimm/access.go @@ -708,7 +708,7 @@ func (j *JIMM) parseAndValidateTag(ctx context.Context, key string) (*ofganames. return tag, nil } tagString := key - tag, err := resolveTag(j.UUID, &j.Database, tagString) + tag, err := resolveTag(j.UUID, j.Database, tagString) if err != nil { zapctx.Debug(ctx, "failed to resolve tuple object", zap.Error(err)) return nil, errors.E(op, errors.CodeFailedToResolveTupleResource, err) diff --git a/internal/jimm/access_test.go b/internal/jimm/access_test.go index 403f84e69..970db626c 100644 --- a/internal/jimm/access_test.go +++ b/internal/jimm/access_test.go @@ -120,17 +120,17 @@ func TestAuditLogAccess(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } + }) + c.Assert(err, qt.IsNil) + ctx := context.Background() - err = j.Database.Migrate(ctx, false) - c.Assert(err, qt.IsNil) i, err := dbmodel.NewIdentity("alice") c.Assert(err, qt.IsNil) adminUser := openfga.NewUser(i, j.OpenFGAClient) @@ -437,15 +437,13 @@ func TestParseAndValidateTag(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) user, _, _, model, _, _, _, _ := createTestControllerEnvironment(ctx, c, j.Database) @@ -484,15 +482,17 @@ func TestResolveTags(t *testing.T) { c := qt.New(t) ctx := context.Background() + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - - err := j.Database.Migrate(ctx, false) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.IsNil) identity, group, controller, model, offer, cloud, _, role := createTestControllerEnvironment(ctx, c, j.Database) @@ -561,7 +561,7 @@ func TestResolveTags(t *testing.T) { for _, tC := range testCases { t.Run(tC.desc, func(t *testing.T) { - jujuTag, err := jimm.ResolveTag(j.UUID, &j.Database, tC.input) + jujuTag, err := jimm.ResolveTag(j.UUID, j.Database, tC.input) c.Assert(err, qt.IsNil) c.Assert(jujuTag, qt.DeepEquals, tC.expected) }) @@ -572,15 +572,17 @@ func TestResolveTupleObjectHandlesErrors(t *testing.T) { c := qt.New(t) ctx := context.Background() + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - - err := j.Database.Migrate(ctx, false) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.IsNil) _, _, controller, model, offer, _, _, _ := createTestControllerEnvironment(ctx, c, j.Database) @@ -632,7 +634,7 @@ func TestResolveTupleObjectHandlesErrors(t *testing.T) { } for i, tc := range tests { t.Run(fmt.Sprintf("test %d", i), func(t *testing.T) { - _, err := jimm.ResolveTag(j.UUID, &j.Database, tc.input) + _, err := jimm.ResolveTag(j.UUID, j.Database, tc.input) c.Assert(err, qt.ErrorMatches, tc.want) }) } @@ -642,15 +644,17 @@ func TestToJAASTag(t *testing.T) { c := qt.New(t) ctx := context.Background() + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - - err := j.Database.Migrate(ctx, false) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.IsNil) user, group, controller, model, applicationOffer, cloud, _, role := createTestControllerEnvironment(ctx, c, j.Database) @@ -704,15 +708,17 @@ func TestToJAASTagNoUUIDResolution(t *testing.T) { c := qt.New(t) ctx := context.Background() + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - - err := j.Database.Migrate(ctx, false) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.IsNil) user, group, controller, model, applicationOffer, cloud, _, role := createTestControllerEnvironment(ctx, c, j.Database) @@ -779,7 +785,7 @@ func TestToJAASTagNoUUIDResolution(t *testing.T) { // // TODO(ale8k): Make this an implicit thing on the JIMM suite per test & refactor the current state. // and make the suite argument an interface of the required calls we use here. -func createTestControllerEnvironment(ctx context.Context, c *qt.C, db db.Database) ( +func createTestControllerEnvironment(ctx context.Context, c *qt.C, db *db.Database) ( dbmodel.Identity, dbmodel.GroupEntry, dbmodel.Controller, @@ -882,15 +888,13 @@ func TestAddGroup(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) dbU, err := dbmodel.NewIdentity(petname.Generate(2, "-"+"canonical.com")) @@ -917,15 +921,13 @@ func TestCountGroups(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) dbU, err := dbmodel.NewIdentity(petname.Generate(2, "-"+"canonical.com")) @@ -949,15 +951,13 @@ func TestGetGroup(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) dbU, err := dbmodel.NewIdentity(petname.Generate(2, "-"+"canonical.com")) @@ -992,15 +992,13 @@ func TestRemoveGroup(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) user, group, _, _, _, _, _, _ := createTestControllerEnvironment(ctx, c, j.Database) @@ -1022,15 +1020,13 @@ func TestRemoveGroupRemovesTuples(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) user, group, controller, model, _, _, _, _ := createTestControllerEnvironment(ctx, c, j.Database) @@ -1106,15 +1102,13 @@ func TestRenameGroup(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) user, group, controller, model, _, _, _, _ := createTestControllerEnvironment(ctx, c, j.Database) @@ -1198,15 +1192,13 @@ func TestListGroups(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) user, group, _, _, _, _, _, _ := createTestControllerEnvironment(ctx, c, j.Database) @@ -1254,15 +1246,13 @@ func TestOpenFGACleanup(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) // run cleanup on an empty authorizaton store diff --git a/internal/jimm/admin_test.go b/internal/jimm/admin_test.go index 9745504d7..e640e966e 100644 --- a/internal/jimm/admin_test.go +++ b/internal/jimm/admin_test.go @@ -21,9 +21,16 @@ import ( func TestLoginDevice(t *testing.T) { c := qt.New(t) mockAuthenticator := jimmtest.NewMockOAuthAuthenticator(c, nil) - jimm := jimm.JIMM{ + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + jimm, err := jimm.New(jimm.Parameters{ + Database: &db.Database{ + DB: jimmtest.PostgresDB(c, func() time.Time { return now }), + }, OAuthAuthenticator: &mockAuthenticator, - } + OpenFGAClient: ofgaClient, + }) + c.Assert(err, qt.IsNil) resp, err := jimm.LoginDevice(context.Background()) c.Assert(err, qt.IsNil) c.Assert(*resp, qt.CmpEquals(cmpopts.IgnoreTypes(time.Time{})), oauth2.DeviceAuthResponse{ @@ -38,10 +45,19 @@ func TestLoginDevice(t *testing.T) { func TestGetDeviceSessionToken(t *testing.T) { c := qt.New(t) pollingChan := make(chan string, 1) + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + mockAuthenticator := jimmtest.NewMockOAuthAuthenticator(c, pollingChan) - jimm := jimm.JIMM{ + jimm, err := jimm.New(jimm.Parameters{ + Database: &db.Database{ + DB: jimmtest.PostgresDB(c, func() time.Time { return now }), + }, OAuthAuthenticator: &mockAuthenticator, - } + OpenFGAClient: ofgaClient, + }) + c.Assert(err, qt.IsNil) + pollingChan <- "user-foo" token, err := jimm.GetDeviceSessionToken(context.Background(), nil) c.Assert(err, qt.IsNil) @@ -58,17 +74,16 @@ func TestLoginClientCredentials(t *testing.T) { mockAuthenticator := jimmtest.NewMockOAuthAuthenticator(c, nil) client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), t.Name()) c.Assert(err, qt.IsNil) - jimm := jimm.JIMM{ + jimm, err := jimm.New(jimm.Parameters{ UUID: "foo", - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OAuthAuthenticator: &mockAuthenticator, OpenFGAClient: client, - } - ctx := context.Background() - err = jimm.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) + ctx := context.Background() invalidClientID := "123@123@" _, err = jimm.LoginClientCredentials(ctx, invalidClientID, "foo-secret") c.Assert(err, qt.ErrorMatches, "invalid client ID") @@ -84,18 +99,18 @@ func TestLoginWithSessionToken(t *testing.T) { mockAuthenticator := jimmtest.NewMockOAuthAuthenticator(c, nil) client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), t.Name()) c.Assert(err, qt.IsNil) - jimm := jimm.JIMM{ + jimm, err := jimm.New(jimm.Parameters{ UUID: "foo", - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OAuthAuthenticator: &mockAuthenticator, OpenFGAClient: client, - } - ctx := context.Background() - err = jimm.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) + ctx := context.Background() + token, err := jwt.NewBuilder(). Subject("alice@canonical.com"). Build() @@ -117,18 +132,18 @@ func TestLoginWithSessionCookie(t *testing.T) { mockAuthenticator := jimmtest.NewMockOAuthAuthenticator(c, nil) client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), t.Name()) c.Assert(err, qt.IsNil) - jimm := jimm.JIMM{ + jimm, err := jimm.New(jimm.Parameters{ UUID: "foo", - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OAuthAuthenticator: &mockAuthenticator, OpenFGAClient: client, - } - ctx := context.Background() - err = jimm.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) + ctx := context.Background() + _, err = jimm.LoginWithSessionCookie(ctx, "") c.Assert(err, qt.ErrorMatches, "missing cookie identity") diff --git a/internal/jimm/applicationoffer_test.go b/internal/jimm/applicationoffer_test.go index d079a38c7..d8ee07ae2 100644 --- a/internal/jimm/applicationoffer_test.go +++ b/internal/jimm/applicationoffer_test.go @@ -329,7 +329,7 @@ func TestRevokeOfferAccess(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - db := db.Database{ + db := &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), } err := db.Migrate(ctx, false) @@ -340,16 +340,17 @@ func TestRevokeOfferAccess(t *testing.T) { jimmUUID := uuid.NewString() - environment := initializeEnvironment(c, ctx, &db, client, jimmUUID) - - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: jimmUUID, OpenFGAClient: client, Database: db, Dialer: &jimmtest.Dialer{ API: &jimmtest.API{}, }, - } + }) + c.Assert(err, qt.IsNil) + + environment := initializeEnvironment(c, ctx, db, client, jimmUUID) if test.setup != nil { test.setup(environment, client) @@ -498,28 +499,27 @@ func TestGrantOfferAccess(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - db := db.Database{ + db := &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), } - err := db.Migrate(ctx, false) - c.Assert(err, qt.IsNil) client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), test.about) c.Assert(err, qt.IsNil) jimmUUID := uuid.NewString() - environment := initializeEnvironment(c, ctx, &db, client, jimmUUID) - authenticatedUser, offerUser, offerURL, grantAccessLevel := test.parameterFunc(environment) - - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: jimmUUID, OpenFGAClient: client, Database: db, Dialer: &jimmtest.Dialer{ API: &jimmtest.API{}, }, - } + }) + c.Assert(err, qt.IsNil) + + environment := initializeEnvironment(c, ctx, db, client, jimmUUID) + authenticatedUser, offerUser, offerURL, grantAccessLevel := test.parameterFunc(environment) err = j.GrantOfferAccess(ctx, openfga.NewUser(&authenticatedUser, client), offerURL, offerUser.ResourceTag(), grantAccessLevel) if test.expectedError == "" { @@ -548,7 +548,7 @@ func TestGetApplicationOfferConsumeDetails(t *testing.T) { ctx := context.Background() now := time.Now().UTC().Round(time.Millisecond) - db := db.Database{ + db := &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), } err = db.Migrate(ctx, false) @@ -647,7 +647,7 @@ func TestGetApplicationOfferConsumeDetails(t *testing.T) { err = openfga.NewUser(uAll, client).SetApplicationOfferAccess(ctx, offer.ResourceTag(), ofganames.ReaderRelation) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, Database: db, @@ -685,7 +685,8 @@ func TestGetApplicationOfferConsumeDetails(t *testing.T) { }, }, }, - } + }) + c.Assert(err, qt.IsNil) tests := []struct { about string @@ -814,10 +815,10 @@ func TestGetApplicationOffer(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, Dialer: &jimmtest.Dialer{ @@ -857,9 +858,7 @@ func TestGetApplicationOffer(t *testing.T) { }, }, }, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) u, err := dbmodel.NewIdentity("alice@canonical.com") @@ -1037,7 +1036,7 @@ func TestOffer(t *testing.T) { getApplicationOffer func(context.Context, *jujuparams.ApplicationOfferAdminDetailsV5) error grantApplicationOfferAccess func(context.Context, string, names.UserTag, jujuparams.OfferAccessPermission) error offer func(context.Context, crossmodel.OfferURL, jujuparams.AddApplicationOffer) error - createEnv func(*qt.C, db.Database, *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) + createEnv func(*qt.C, *db.Database, *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) }{{ about: "all ok", getApplicationOffer: func(_ context.Context, details *jujuparams.ApplicationOfferAdminDetailsV5) error { @@ -1073,7 +1072,7 @@ func TestOffer(t *testing.T) { offer: func(context.Context, crossmodel.OfferURL, jujuparams.AddApplicationOffer) error { return nil }, - createEnv: func(c *qt.C, db db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { + createEnv: func(c *qt.C, db *db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { ctx := context.Background() u, err := dbmodel.NewIdentity("alice@canonical.com") @@ -1163,7 +1162,7 @@ func TestOffer(t *testing.T) { offer: func(context.Context, crossmodel.OfferURL, jujuparams.AddApplicationOffer) error { return errors.E("a silly error") }, - createEnv: func(c *qt.C, db db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { + createEnv: func(c *qt.C, db *db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { ctx := context.Background() u, err := dbmodel.NewIdentity("alice@canonical.com") @@ -1250,7 +1249,7 @@ func TestOffer(t *testing.T) { offer: func(context.Context, crossmodel.OfferURL, jujuparams.AddApplicationOffer) error { return nil }, - createEnv: func(c *qt.C, db db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { + createEnv: func(c *qt.C, db *db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { u, err := dbmodel.NewIdentity("alice@canonical.com") c.Assert(err, qt.IsNil) @@ -1282,7 +1281,7 @@ func TestOffer(t *testing.T) { offer: func(context.Context, crossmodel.OfferURL, jujuparams.AddApplicationOffer) error { return errors.E(errors.CodeNotFound, "application test-app") }, - createEnv: func(c *qt.C, db db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { + createEnv: func(c *qt.C, db *db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { ctx := context.Background() u, err := dbmodel.NewIdentity("alice@canonical.com") @@ -1371,7 +1370,7 @@ func TestOffer(t *testing.T) { offer: func(context.Context, crossmodel.OfferURL, jujuparams.AddApplicationOffer) error { return nil }, - createEnv: func(c *qt.C, db db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { + createEnv: func(c *qt.C, db *db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { ctx := context.Background() u, err := dbmodel.NewIdentity("alice@canonical.com") @@ -1462,7 +1461,7 @@ func TestOffer(t *testing.T) { offer: func(context.Context, crossmodel.OfferURL, jujuparams.AddApplicationOffer) error { return nil }, - createEnv: func(c *qt.C, db db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { + createEnv: func(c *qt.C, db *db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { ctx := context.Background() u, err := dbmodel.NewIdentity("alice@canonical.com") @@ -1549,7 +1548,7 @@ func TestOffer(t *testing.T) { offer: func(context.Context, crossmodel.OfferURL, jujuparams.AddApplicationOffer) error { return errors.E("application offer already exists") }, - createEnv: func(c *qt.C, db db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { + createEnv: func(c *qt.C, db *db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { ctx := context.Background() u, err := dbmodel.NewIdentity("alice@canonical.com") @@ -1639,19 +1638,18 @@ func TestOffer(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), test.about) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ - Database: db.Database{ + j, err := jimm.New(jimm.Parameters{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, Dialer: &jimmtest.Dialer{ API: api, }, OpenFGAClient: client, - } + }) + c.Assert(err, qt.IsNil) ctx := context.Background() - err = j.Database.Migrate(ctx, false) - c.Assert(err, qt.IsNil) u, offerArgs, expectedOffer, errorAssertion := test.createEnv(c, j.Database, client) @@ -1678,7 +1676,7 @@ func TestOfferAssertOpenFGARelationsExist(t *testing.T) { ctx := context.Background() now := time.Now().UTC().Round(time.Millisecond) - createEnv := func(c *qt.C, db db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { + createEnv := func(c *qt.C, db *db.Database, client *openfga.OFGAClient) (dbmodel.Identity, jimm.AddApplicationOfferParams, dbmodel.ApplicationOffer, func(*qt.C, error)) { ctx := context.Background() u, err := dbmodel.NewIdentity("alice@canonical.com") @@ -1797,9 +1795,9 @@ func TestOfferAssertOpenFGARelationsExist(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, Dialer: &jimmtest.Dialer{ @@ -1807,9 +1805,7 @@ func TestOfferAssertOpenFGARelationsExist(t *testing.T) { UUID: "00000000-0000-0000-0000-0000-0000000000001", }, OpenFGAClient: client, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) u, offerArgs, expectedOffer, _ := createEnv(c, j.Database, client) @@ -1983,7 +1979,7 @@ func TestDestroyOffer(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - db := db.Database{ + db := &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), } err := db.Migrate(ctx, false) @@ -1994,10 +1990,10 @@ func TestDestroyOffer(t *testing.T) { jimmUUID := uuid.NewString() - environment := initializeEnvironment(c, ctx, &db, client, jimmUUID) + environment := initializeEnvironment(c, ctx, db, client, jimmUUID) authenticatedUser, offerURL := test.parameterFunc(environment) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: jimmUUID, Database: db, Dialer: &jimmtest.Dialer{ @@ -2013,7 +2009,8 @@ func TestDestroyOffer(t *testing.T) { }, }, OpenFGAClient: client, - } + }) + c.Assert(err, qt.IsNil) if test.destroyError != "" { select { @@ -2107,7 +2104,7 @@ func TestFindApplicationOffers(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - db := db.Database{ + db := &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), } err := db.Migrate(ctx, false) @@ -2118,10 +2115,10 @@ func TestFindApplicationOffers(t *testing.T) { jimmUUID := uuid.NewString() - environment := initializeEnvironment(c, ctx, &db, client, jimmUUID) + environment := initializeEnvironment(c, ctx, db, client, jimmUUID) user, accessLevel, filters := test.parameterFunc(environment) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: jimmUUID, Database: db, Dialer: &jimmtest.Dialer{ @@ -2135,7 +2132,8 @@ func TestFindApplicationOffers(t *testing.T) { }, }, OpenFGAClient: client, - } + }) + c.Assert(err, qt.IsNil) offers, err := j.FindApplicationOffers(ctx, openfga.NewUser(&user, client), filters...) if test.expectedError == "" { @@ -2293,14 +2291,14 @@ func TestListApplicationOffers(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - db := db.Database{ + db := &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), } err = db.Migrate(ctx, false) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, listApplicationsTestEnv) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, Database: db, @@ -2416,7 +2414,8 @@ func TestListApplicationOffers(t *testing.T) { }, }, }, - } + }) + c.Assert(err, qt.IsNil) env.PopulateDBAndPermissions(c, j.ResourceTag(), db, client) tuples := []openfga.Tuple{{ Object: ofganames.ConvertTag(names.NewUserTag("alice@canonical.com")), diff --git a/internal/jimm/audit_log.go b/internal/jimm/audit_log.go index 7bd4d5cab..a66deb3c9 100644 --- a/internal/jimm/audit_log.go +++ b/internal/jimm/audit_log.go @@ -130,7 +130,7 @@ func (o recorder) HandleReply(r rpc.Request, header *rpc.Header, body interface{ // on a defined retention period. The retention period is in DAYS. type auditLogCleanupService struct { auditLogRetentionPeriodInDays int - db db.Database + db *db.Database } // pollTimeOfDay holds the time hour, minutes and seconds to poll at. @@ -146,7 +146,7 @@ var pollDuration = pollTimeOfDay{ // NewAuditLogCleanupService returns a service capable of cleaning up audit logs // on a defined retention period. The retention period is in DAYS. -func NewAuditLogCleanupService(db db.Database, auditLogRetentionPeriodInDays int) *auditLogCleanupService { +func NewAuditLogCleanupService(db *db.Database, auditLogRetentionPeriodInDays int) *auditLogCleanupService { return &auditLogCleanupService{ auditLogRetentionPeriodInDays: auditLogRetentionPeriodInDays, db: db, diff --git a/internal/jimm/audit_log_test.go b/internal/jimm/audit_log_test.go index 5872b0a8f..b1bd08083 100644 --- a/internal/jimm/audit_log_test.go +++ b/internal/jimm/audit_log_test.go @@ -22,7 +22,7 @@ func TestAuditLogCleanupServicePurgesLogs(t *testing.T) { ctx := context.Background() now := time.Now().UTC().Round(time.Millisecond) - db := db.Database{ + db := &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), } diff --git a/internal/jimm/cloud.go b/internal/jimm/cloud.go index b485ad23f..1cb61e9ac 100644 --- a/internal/jimm/cloud.go +++ b/internal/jimm/cloud.go @@ -160,7 +160,7 @@ func (j *JIMM) AddCloudToController(ctx context.Context, user *openfga.User, con return errors.E(op, err) } - if err := validateCloudRegion(ctx, &j.Database, user, cloud, controllerName); err != nil { + if err := validateCloudRegion(ctx, j.Database, user, cloud, controllerName); err != nil { return errors.E(op, err) } diff --git a/internal/jimm/cloud_test.go b/internal/jimm/cloud_test.go index 74e391d32..3602289c9 100644 --- a/internal/jimm/cloud_test.go +++ b/internal/jimm/cloud_test.go @@ -29,15 +29,13 @@ func TestGetCloud(t *testing.T) { ctx := context.Background() now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) aliceIdentity, err := dbmodel.NewIdentity("alice@canonical.com") @@ -157,15 +155,13 @@ func TestForEachCloud(t *testing.T) { ctx := context.Background() now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: "test-jimm-uuid", OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) aliceIdentity, err := dbmodel.NewIdentity("alice@canonical.com") @@ -583,14 +579,15 @@ func TestAddHostedCloud(t *testing.T) { Err: test.dialError, API: api, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, OpenFGAClient: client, - } + }) + c.Assert(err, qt.IsNil) // since dialer is set up to dial a controller with UUID set to // jimmtest.DefaultControllerUUID we need to add a controller @@ -598,9 +595,6 @@ func TestAddHostedCloud(t *testing.T) { err = client.AddController(context.Background(), j.ResourceTag(), names.NewControllerTag(jimmtest.DefaultControllerUUID)) c.Assert(err, qt.IsNil) - err = j.Database.Migrate(ctx, false) - c.Assert(err, qt.IsNil) - env := jimmtest.ParseEnvironment(c, addHostedCloudTestEnv) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) @@ -863,14 +857,15 @@ func TestAddCloudToController(t *testing.T) { Err: test.dialError, API: api, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, OpenFGAClient: client, - } + }) + c.Assert(err, qt.IsNil) // since dialer is set up to dial a controller with UUID set to // jimmtest.DefaultControllerUUID we need to add a controller @@ -878,9 +873,6 @@ func TestAddCloudToController(t *testing.T) { err = client.AddController(context.Background(), j.ResourceTag(), names.NewControllerTag(jimmtest.DefaultControllerUUID)) c.Assert(err, qt.IsNil) - err = j.Database.Migrate(ctx, false) - c.Assert(err, qt.IsNil) - env := jimmtest.ParseEnvironment(c, addHostedCloudTestEnv) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) @@ -1032,15 +1024,14 @@ func TestGrantCloudAccess(t *testing.T) { API: &jimmtest.API{}, Err: tt.dialError, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: jimmtest.ControllerUUID, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, OpenFGAClient: client, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) @@ -1333,16 +1324,14 @@ func TestRevokeCloudAccess(t *testing.T) { API: &jimmtest.API{}, Err: tt.dialError, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: jimmtest.ControllerUUID, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, OpenFGAClient: client, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) @@ -1487,15 +1476,14 @@ func TestRemoveCloud(t *testing.T) { }, Err: test.dialError, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, OpenFGAClient: client, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) @@ -1727,15 +1715,14 @@ func TestUpdateCloud(t *testing.T) { UUID: "00000001-0000-0000-0000-000000000001", AgentVersion: "1", } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, OpenFGAClient: client, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) @@ -1921,15 +1908,14 @@ func TestRemoveFromControllerCloud(t *testing.T) { }, Err: test.dialError, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, OpenFGAClient: client, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) diff --git a/internal/jimm/cloudcredential_test.go b/internal/jimm/cloudcredential_test.go index eab46b4db..c65aff962 100644 --- a/internal/jimm/cloudcredential_test.go +++ b/internal/jimm/cloudcredential_test.go @@ -778,20 +778,19 @@ func TestUpdateCloudCredential(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, Dialer: &jimmtest.Dialer{ API: api, }, OpenFGAClient: client, - } + }) + c.Assert(err, qt.IsNil) ctx := context.Background() - err = j.Database.Migrate(ctx, false) - c.Assert(err, qt.IsNil) u, arg, expectedCredential, expectedError := test.createEnv(c, j, client) user := openfga.NewUser(u, client) @@ -835,18 +834,16 @@ users: - username: alice@canonical.com controller-access: superuser `) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ API: &jimmtest.API{}, }, OpenFGAClient: client, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) u := env.User("alice@canonical.com").DBObject(c, j.Database) @@ -1241,23 +1238,21 @@ func TestRevokeCloudCredential(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), test.about) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, Dialer: &jimmtest.Dialer{ API: api, }, OpenFGAClient: client, - } - - ctx := context.Background() - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) user, tag, expectedError := test.createEnv(c, j, client) + ctx := context.Background() err = j.RevokeCloudCredential(ctx, user, tag, false) if expectedError == "" { c.Assert(err, qt.Equals, nil) @@ -1375,21 +1370,18 @@ func TestGetCloudCredential(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), test.about) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: client, - } - - ctx := context.Background() - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) u, tag, expectedCredential, expectedError := test.createEnv(c, j, client) user := openfga.NewUser(u, client) - credential, err := j.GetCloudCredential(ctx, user, tag) + credential, err := j.GetCloudCredential(context.Background(), user, tag) if expectedError == "" { c.Assert(err, qt.Equals, nil) c.Assert(credential, jimmtest.DBObjectEquals, &expectedCredential) @@ -1484,17 +1476,16 @@ func TestForEachUserCloudCredential(t *testing.T) { c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, test.env) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ API: &jimmtest.API{}, }, OpenFGAClient: client, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) u := env.User(test.username).DBObject(c, j.Database) @@ -1626,17 +1617,16 @@ func TestGetCloudCredentialAttributes(t *testing.T) { c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, getCloudCredentialAttributesEnv) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ API: &jimmtest.API{}, }, OpenFGAClient: client, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) u := env.User("bob@canonical.com").DBObject(c, j.Database) @@ -1673,17 +1663,17 @@ func TestCloudCredentialAttributeStore(t *testing.T) { attrStore := testCloudCredentialAttributeStore{ attrs: make(map[string]map[string]string), } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ API: &jimmtest.API{}, }, CredentialStore: attrStore, - } - err = j.Database.Migrate(ctx, false) + OpenFGAClient: client, + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, `clouds: diff --git a/internal/jimm/clouddefaults_test.go b/internal/jimm/clouddefaults_test.go index 09802944d..b6b0c0333 100644 --- a/internal/jimm/clouddefaults_test.go +++ b/internal/jimm/clouddefaults_test.go @@ -25,6 +25,9 @@ func TestSetCloudDefaults(t *testing.T) { ctx := context.Background() now := time.Now() + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + type testConfig struct { user *dbmodel.Identity cloud names.CloudTag @@ -232,12 +235,12 @@ func TestSetCloudDefaults(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - j := &jimm.JIMM{ - Database: db.Database{ + j, err := jimm.New(jimm.Parameters{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - err := j.Database.Migrate(ctx, true) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.Equals, nil) testConfig := test.setup(c, j) @@ -268,6 +271,9 @@ func TestUnsetCloudDefaults(t *testing.T) { ctx := context.Background() now := time.Now() + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + type testConfig struct { user *dbmodel.Identity cloud names.CloudTag @@ -425,12 +431,12 @@ func TestUnsetCloudDefaults(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - j := &jimm.JIMM{ - Database: db.Database{ + j, err := jimm.New(jimm.Parameters{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - err := j.Database.Migrate(ctx, true) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.Equals, nil) testConfig := test.setup(c, j) @@ -461,12 +467,15 @@ func TestModelDefaultsForCloud(t *testing.T) { ctx := context.Background() now := time.Now() - j := &jimm.JIMM{ - Database: db.Database{ + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + + j, err := jimm.New(jimm.Parameters{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - err := j.Database.Migrate(ctx, true) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.Equals, nil) user, err := dbmodel.NewIdentity("bob@canonical.com") diff --git a/internal/jimm/controller_test.go b/internal/jimm/controller_test.go index bcab83215..b5c7a3d85 100644 --- a/internal/jimm/controller_test.go +++ b/internal/jimm/controller_test.go @@ -133,20 +133,19 @@ func TestAddController(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, Dialer: &jimmtest.Dialer{ API: api, }, OpenFGAClient: client, - } + }) + c.Assert(err, qt.IsNil) ctx := context.Background() - err = j.Database.Migrate(ctx, false) - c.Assert(err, qt.IsNil) u, err := dbmodel.NewIdentity("alice@canonical.com") c.Assert(err, qt.IsNil) @@ -299,9 +298,9 @@ func TestAddControllerWithVault(t *testing.T) { ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, Dialer: &jimmtest.Dialer{ @@ -309,11 +308,10 @@ func TestAddControllerWithVault(t *testing.T) { }, CredentialStore: store, OpenFGAClient: ofgaClient, - } + }) + c.Assert(err, qt.IsNil) ctx := context.Background() - err = j.Database.Migrate(ctx, false) - c.Assert(err, qt.IsNil) u, err := dbmodel.NewIdentity("alice@canonical.com") c.Assert(err, qt.IsNil) @@ -408,15 +406,13 @@ func TestEarliestControllerVersion(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: client, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, testEarliestControllerVersionEnv) @@ -1018,9 +1014,9 @@ func TestImportModel(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), test.about) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ @@ -1028,11 +1024,11 @@ func TestImportModel(t *testing.T) { UUID: test.expectedModel.Controller.UUID, }, OpenFGAClient: client, - } - ctx := context.Background() - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) + ctx := context.Background() + env := jimmtest.ParseEnvironment(c, testImportModelEnv) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) @@ -1087,6 +1083,9 @@ users: func TestSetControllerConfig(t *testing.T) { c := qt.New(t) + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + tests := []struct { about string user string @@ -1139,14 +1138,13 @@ func TestSetControllerConfig(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, - } - ctx := context.Background() - err := j.Database.Migrate(ctx, false) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, testControllerConfigEnv) @@ -1156,6 +1154,8 @@ func TestSetControllerConfig(t *testing.T) { user := openfga.NewUser(&dbUser, nil) user.JimmAdmin = test.jimmAdmin + ctx := context.Background() + err = j.SetControllerConfig(ctx, user, test.args) if test.expectedError == "" { c.Assert(err, qt.IsNil) @@ -1176,6 +1176,9 @@ func TestSetControllerConfig(t *testing.T) { func TestGetControllerConfig(t *testing.T) { c := qt.New(t) + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + tests := []struct { about string user string @@ -1216,14 +1219,13 @@ func TestGetControllerConfig(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, - } - ctx := context.Background() - err := j.Database.Migrate(ctx, false) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, testImportModelEnv) @@ -1237,6 +1239,8 @@ func TestGetControllerConfig(t *testing.T) { user := openfga.NewUser(&dbUser, nil) user.JimmAdmin = test.jimmAdmin + ctx := context.Background() + err = j.SetControllerConfig(ctx, superuser, jujuparams.ControllerConfigSet{ Config: map[string]interface{}{ "key1": "value1", @@ -1316,6 +1320,9 @@ models: func TestUpdateMigratedModel(t *testing.T) { c := qt.New(t) + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + tests := []struct { about string user string @@ -1364,9 +1371,9 @@ func TestUpdateMigratedModel(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ @@ -1374,9 +1381,8 @@ func TestUpdateMigratedModel(t *testing.T) { ModelInfo_: test.modelInfo, }, }, - } - ctx := context.Background() - err := j.Database.Migrate(ctx, false) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, testUpdateMigratedModelEnv) @@ -1386,6 +1392,8 @@ func TestUpdateMigratedModel(t *testing.T) { user := openfga.NewUser(&dbUser, nil) user.JimmAdmin = test.jimmAdmin + ctx := context.Background() + err = j.UpdateMigratedModel(ctx, user, test.model, test.targetController) if test.expectedError != "" { c.Assert(err, qt.ErrorMatches, test.expectedError) @@ -1422,17 +1430,17 @@ func TestGetControllerAccess(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, OpenFGAClient: client, - } - ctx := context.Background() - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) + ctx := context.Background() + env := jimmtest.ParseEnvironment(c, testGetControllerAccessEnv) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) @@ -1724,17 +1732,14 @@ func TestInitiateMigration(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, OpenFGAClient: client, Dialer: &testDialer{}, - } - - ctx := context.Background() - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, testInitiateMigrationEnv) diff --git a/internal/jimm/export_test.go b/internal/jimm/export_test.go index 6e3b27b63..1abcc4ef4 100644 --- a/internal/jimm/export_test.go +++ b/internal/jimm/export_test.go @@ -28,7 +28,7 @@ func WatchController(w *Watcher, ctx context.Context, ctl *dbmodel.Controller) e return w.watchController(ctx, ctl) } -func NewWatcherWithControllerUnavailableChan(db db.Database, dialer Dialer, pubsub Publisher, testChannel chan error) *Watcher { +func NewWatcherWithControllerUnavailableChan(db *db.Database, dialer Dialer, pubsub Publisher, testChannel chan error) *Watcher { return &Watcher{ Pubsub: pubsub, Database: db, @@ -37,7 +37,7 @@ func NewWatcherWithControllerUnavailableChan(db db.Database, dialer Dialer, pubs } } -func NewWatcherWithDeltaProcessedChannel(db db.Database, dialer Dialer, pubsub Publisher, testChannel chan bool) *Watcher { +func NewWatcherWithDeltaProcessedChannel(db *db.Database, dialer Dialer, pubsub Publisher, testChannel chan bool) *Watcher { return &Watcher{ Pubsub: pubsub, Database: db, diff --git a/internal/jimm/identity_test.go b/internal/jimm/identity_test.go index 7799392cb..e6a561102 100644 --- a/internal/jimm/identity_test.go +++ b/internal/jimm/identity_test.go @@ -26,15 +26,13 @@ func TestFetchIdentity(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) user, _, _, _, _, _, _, _ := createTestControllerEnvironment(ctx, c, j.Database) @@ -54,15 +52,13 @@ func TestListIdentities(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) u := openfga.NewUser(&dbmodel.Identity{Name: "admin@canonical.com"}, ofgaClient) @@ -139,15 +135,13 @@ func TestCountIdentities(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) u := openfga.NewUser(&dbmodel.Identity{Name: "admin@canonical.com"}, ofgaClient) diff --git a/internal/jimm/identitymodeldefaults_test.go b/internal/jimm/identitymodeldefaults_test.go index b32008b65..ccbf5e233 100644 --- a/internal/jimm/identitymodeldefaults_test.go +++ b/internal/jimm/identitymodeldefaults_test.go @@ -23,6 +23,9 @@ func TestSetIdentityModelDefaults(t *testing.T) { ctx := context.Background() now := time.Now() + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + type testConfig struct { identity *dbmodel.Identity defaults map[string]interface{} @@ -119,12 +122,12 @@ func TestSetIdentityModelDefaults(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - j := &jimm.JIMM{ - Database: db.Database{ + j, err := jimm.New(jimm.Parameters{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - err := j.Database.Migrate(ctx, true) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.Equals, nil) testConfig := test.setup(c, j) @@ -151,6 +154,9 @@ func TestIdentityModelDefaults(t *testing.T) { ctx := context.Background() now := time.Now() + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + type testConfig struct { identity *dbmodel.Identity expectedError string @@ -206,12 +212,12 @@ func TestIdentityModelDefaults(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - j := &jimm.JIMM{ - Database: db.Database{ + j, err := jimm.New(jimm.Parameters{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - err := j.Database.Migrate(ctx, true) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.Equals, nil) testConfig := test.setup(c, j) diff --git a/internal/jimm/jimm.go b/internal/jimm/jimm.go index 2095b64f3..18781a1ce 100644 --- a/internal/jimm/jimm.go +++ b/internal/jimm/jimm.go @@ -29,6 +29,7 @@ import ( "github.com/canonical/jimm/v3/internal/dbmodel" "github.com/canonical/jimm/v3/internal/errors" "github.com/canonical/jimm/v3/internal/jimm/credentials" + "github.com/canonical/jimm/v3/internal/jimm/role" "github.com/canonical/jimm/v3/internal/jimmjwx" "github.com/canonical/jimm/v3/internal/openfga" ofganames "github.com/canonical/jimm/v3/internal/openfga/names" @@ -41,16 +42,13 @@ var ( } ) -// A JIMM provides the business logic for managing resources in the JAAS -// system. A single JIMM instance is shared by all concurrent API -// connections therefore the JIMM object itself does not contain any per- -// request state. -type JIMM struct { +// Parameters holds parameters for the JIMM type. +type Parameters struct { // Database is the database used by JIMM, this provides direct access // to the data store. Any client accessing the database directly is // responsible for ensuring that the authenticated user has access to // the data. - Database db.Database + Database *db.Database // Dialer is the API dialer JIMM uses to contact juju controllers. if // this is not configured all connection attempts will fail. @@ -87,52 +85,6 @@ type JIMM struct { // OAuthAuthenticator is responsible for handling authentication // via OAuth2.0 AND JWT access tokens to JIMM. OAuthAuthenticator OAuthAuthenticator - - // RoleManager provides a means to manage roles within JIMM. - RoleManager RoleManager -} - -// RoleManager provides a means to manage roles within JIMM. -type RoleManager interface { - // AddRole adds a role to JIMM. - AddRole(ctx context.Context, user *openfga.User, roleName string) (*dbmodel.RoleEntry, error) - // GetRoleByUUID returns a role based on the provided UUID. - GetRoleByUUID(ctx context.Context, user *openfga.User, uuid string) (*dbmodel.RoleEntry, error) - // GetRoleByName returns a role based on the provided name. - GetRoleByName(ctx context.Context, user *openfga.User, name string) (*dbmodel.RoleEntry, error) - // RemoveRole removes the role from JIMM in both the store and authorisation store. - RemoveRole(ctx context.Context, user *openfga.User, roleName string) error - // RenameRole renames a role in JIMM's DB. - RenameRole(ctx context.Context, user *openfga.User, uuid, newName string) error - // ListRoles returns a list of roles known to JIMM. - // `match` will filter the list fuzzy matching role's name or uuid. - ListRoles(ctx context.Context, user *openfga.User, pagination pagination.LimitOffsetPagination, match string) ([]dbmodel.RoleEntry, error) - // CountRoles returns the number of roles that exist. - CountRoles(ctx context.Context, user *openfga.User) (int, error) -} - -// ResourceTag returns JIMM's controller tag stating its UUID. -func (j *JIMM) ResourceTag() names.ControllerTag { - return names.NewControllerTag(j.UUID) -} - -// DB returns the database used by JIMM. -func (j *JIMM) DB() *db.Database { - return &j.Database -} - -// PubsubHub returns the pub-sub hub used for buffering model summaries. -func (j *JIMM) PubSubHub() *pubsub.Hub { - return j.Pubsub -} - -// AuthorizationClient return the OpenFGA client used by JIMM. -func (j *JIMM) AuthorizationClient() *openfga.OFGAClient { - return j.OpenFGAClient -} - -func (j *JIMM) GetRoleManager() RoleManager { - return j.RoleManager } // OAuthAuthenticator is responsible for handling authentication @@ -193,6 +145,92 @@ type OAuthAuthenticator interface { AuthenticateBrowserSession(ctx context.Context, w http.ResponseWriter, req *http.Request) (context.Context, error) } +// RoleManager provides a means to manage roles within JIMM. +type RoleManager interface { + // AddRole adds a role to JIMM. + AddRole(ctx context.Context, user *openfga.User, roleName string) (*dbmodel.RoleEntry, error) + // GetRoleByUUID returns a role based on the provided UUID. + GetRoleByUUID(ctx context.Context, user *openfga.User, uuid string) (*dbmodel.RoleEntry, error) + // GetRoleByName returns a role based on the provided name. + GetRoleByName(ctx context.Context, user *openfga.User, name string) (*dbmodel.RoleEntry, error) + // RemoveRole removes the role from JIMM in both the store and authorisation store. + RemoveRole(ctx context.Context, user *openfga.User, roleName string) error + // RenameRole renames a role in JIMM's DB. + RenameRole(ctx context.Context, user *openfga.User, uuid, newName string) error + // ListRoles returns a list of roles known to JIMM. + // `match` will filter the list fuzzy matching role's name or uuid. + ListRoles(ctx context.Context, user *openfga.User, pagination pagination.LimitOffsetPagination, match string) ([]dbmodel.RoleEntry, error) + // CountRoles returns the number of roles that exist. + CountRoles(ctx context.Context, user *openfga.User) (int, error) +} + +// Option modifies JIMM returned by the constructor. +type Option func(*JIMM) + +// RoleManagerOption replaces the role manager in the returned JIMM with the specified one. +var RoleManagerOption = func(rm RoleManager) Option { + return func(j *JIMM) { + j.RoleManager = rm + } +} + +// New returns a new instance of JIMM based on the provided parameters and options. +func New(p Parameters, options ...Option) (*JIMM, error) { + j := &JIMM{ + Parameters: p, + } + + if err := j.Database.Migrate(context.Background(), false); err != nil { + return nil, errors.E(err) + } + + roleManager, err := role.NewRoleManager(j.Database, p.OpenFGAClient) + if err != nil { + return nil, err + } + j.RoleManager = roleManager + for _, option := range options { + option(j) + } + + return j, nil +} + +// A JIMM provides the business logic for managing resources in the JAAS +// system. A single JIMM instance is shared by all concurrent API +// connections therefore the JIMM object itself does not contain any per- +// request state. +type JIMM struct { + Parameters + + // RoleManager provides a means to manage roles within JIMM. + RoleManager RoleManager +} + +// ResourceTag returns JIMM's controller tag stating its UUID. +func (j *JIMM) ResourceTag() names.ControllerTag { + return names.NewControllerTag(j.UUID) +} + +// DB returns the database used by JIMM. +func (j *JIMM) DB() *db.Database { + return j.Database +} + +// PubsubHub returns the pub-sub hub used for buffering model summaries. +func (j *JIMM) PubSubHub() *pubsub.Hub { + return j.Pubsub +} + +// AuthorizationClient return the OpenFGA client used by JIMM. +func (j *JIMM) AuthorizationClient() *openfga.OFGAClient { + return j.OpenFGAClient +} + +func (j *JIMM) GetRoleManager() RoleManager { + return j.RoleManager +} + // GetCredentialStore returns the credential store used by JIMM. func (j *JIMM) GetCredentialStore() credentials.CredentialStore { return j.CredentialStore @@ -623,7 +661,7 @@ func (j *JIMM) FullModelStatus(ctx context.Context, user *openfga.User, modelTag type migrationControllerID = uint -func fillMigrationTarget(db db.Database, credStore credentials.CredentialStore, controllerName string) (jujuparams.MigrationTargetInfo, migrationControllerID, error) { +func fillMigrationTarget(db *db.Database, credStore credentials.CredentialStore, controllerName string) (jujuparams.MigrationTargetInfo, migrationControllerID, error) { dbController := dbmodel.Controller{ Name: controllerName, } diff --git a/internal/jimm/jimm_test.go b/internal/jimm/jimm_test.go index 18ecf5cf8..e995901f1 100644 --- a/internal/jimm/jimm_test.go +++ b/internal/jimm/jimm_test.go @@ -32,19 +32,17 @@ func TestFindAuditEvents(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, OpenFGAClient: client, - } + }) + c.Assert(err, qt.Equals, nil) ctx := context.Background() - err = j.Database.Migrate(ctx, true) - c.Assert(err, qt.Equals, nil) - alice, err := dbmodel.NewIdentity("alice@canonical.com") c.Assert(err, qt.IsNil) @@ -213,13 +211,16 @@ func TestControllerInfo(t *testing.T) { ctx := context.Background() now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - err := j.Database.Migrate(ctx, false) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, testControllersEnv) env.PopulateDB(c, j.Database) @@ -241,15 +242,13 @@ func TestListControllers(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: client, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, testControllersEnv) @@ -329,15 +328,13 @@ func TestSetControllerDeprecated(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: client, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, testSetControllerDeprecatedEnv) @@ -440,6 +437,9 @@ func TestRemoveController(t *testing.T) { ctx := context.Background() now := time.Now().UTC().Round(time.Millisecond) + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + tests := []struct { about string user string @@ -481,14 +481,13 @@ func TestRemoveController(t *testing.T) { for _, test := range tests { c.Run(test.about, func(c *qt.C) { - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - - err := j.Database.Migrate(ctx, false) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, removeControllerTestEnv) @@ -577,14 +576,16 @@ func TestRemoveAndAddController(t *testing.T) { ctx := context.Background() now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, - } - - err := j.Database.Migrate(ctx, false) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, removeAndAddControllerTestEnv) @@ -650,6 +651,9 @@ func TestFullModelStatus(t *testing.T) { ctx := context.Background() now := time.Now().UTC().Round(time.Millisecond) + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + fullStatus := jujuparams.FullStatus{ Model: jujuparams.ModelStatusInfo{ Name: "model-1", @@ -734,17 +738,16 @@ func TestFullModelStatus(t *testing.T) { Status_: test.statusFunc, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, Dialer: &jimmtest.Dialer{ API: api, }, - } - - err := j.Database.Migrate(ctx, false) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, fullModelStatusTestEnv) @@ -808,7 +811,7 @@ func TestFillMigrationTarget(t *testing.T) { } for _, test := range tests { c.Run(test.about, func(c *qt.C) { - db := db.Database{ + db := &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), } err := db.Migrate(ctx, false) @@ -871,6 +874,9 @@ func TestInitiateInternalMigration(t *testing.T) { ctx := context.Background() now := time.Now().UTC().Round(time.Millisecond) + ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) + c.Assert(err, qt.IsNil) + tests := []struct { about string user string @@ -897,20 +903,19 @@ func TestInitiateInternalMigration(t *testing.T) { err := store.PutControllerCredentials(context.Background(), test.migrateInfo.TargetController, "admin", "test-secret") c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, CredentialStore: store, - } - err = j.Database.Migrate(ctx, false) + OpenFGAClient: ofgaClient, + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, InitiateMigrationTestEnv) env.PopulateDB(c, j.Database) - err = j.Database.Migrate(ctx, false) - c.Assert(err, qt.IsNil) + dbUser := env.User(test.user).DBObject(c, j.Database) user := openfga.NewUser(&dbUser, nil) mt, err := names.ParseModelTag(test.migrateInfo.ModelTag) diff --git a/internal/jimm/model_status_parser_test.go b/internal/jimm/model_status_parser_test.go index b1b361e83..5b4cbbae2 100644 --- a/internal/jimm/model_status_parser_test.go +++ b/internal/jimm/model_status_parser_test.go @@ -329,9 +329,9 @@ func TestQueryModelsJq(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: client, @@ -429,9 +429,7 @@ func TestQueryModelsJq(t *testing.T) { }, }, }, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, crossModelQueryEnv) diff --git a/internal/jimm/model_test.go b/internal/jimm/model_test.go index 1a4321495..544ed2f42 100644 --- a/internal/jimm/model_test.go +++ b/internal/jimm/model_test.go @@ -1086,20 +1086,20 @@ func TestAddModel(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), test.name) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ API: api, }, OpenFGAClient: client, - } - ctx := context.Background() - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) + ctx := context.Background() + env := jimmtest.ParseEnvironment(c, test.env) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) @@ -1223,14 +1223,13 @@ func TestGetModel(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), t.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, getModelTestEnv) @@ -1427,15 +1426,13 @@ func TestModelInfo(t *testing.T) { for _, test := range modelInfoTests { c.Run(test.name, func(c *qt.C) { - ctx := context.Background() - client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), test.name) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ @@ -1483,8 +1480,7 @@ func TestModelInfo(t *testing.T) { }, }, }, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, test.env) @@ -1606,8 +1602,6 @@ func TestModelStatus(t *testing.T) { for _, test := range modelStatusTests { c.Run(test.name, func(c *qt.C) { - ctx := context.Background() - dialer := &jimmtest.Dialer{ API: &jimmtest.API{ ModelStatus_: test.modelStatus, @@ -1617,15 +1611,14 @@ func TestModelStatus(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), test.name) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, test.env) @@ -1767,18 +1760,16 @@ func TestForEachUserModel(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ API: &jimmtest.API{}, }, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, forEachModelTestEnv) @@ -1907,17 +1898,16 @@ func TestForEachModel(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ API: &jimmtest.API{}, }, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, forEachModelTestEnv) @@ -2183,15 +2173,14 @@ func TestGrantModelAccess(t *testing.T) { API: &jimmtest.API{}, Err: tt.dialError, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: jimmtest.ControllerUUID, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, OpenFGAClient: client, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) @@ -2904,15 +2893,14 @@ func TestRevokeModelAccess(t *testing.T) { API: &jimmtest.API{}, Err: tt.dialError, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: jimmtest.ControllerUUID, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, OpenFGAClient: client, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env.PopulateDBAndPermissions(c, j.ResourceTag(), j.Database, client) @@ -3090,15 +3078,14 @@ func TestDestroyModel(t *testing.T) { client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name(), test.name) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, test.env) @@ -3215,16 +3202,14 @@ func TestDumpModel(t *testing.T) { }, Err: test.dialError, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, test.env) @@ -3328,16 +3313,14 @@ func TestDumpModelDB(t *testing.T) { }, Err: test.dialError, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, test.env) @@ -3447,16 +3430,14 @@ func TestValidateModelUpgrade(t *testing.T) { Err: test.dialError, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, test.env) @@ -3670,15 +3651,14 @@ func TestUpdateModelCredential(t *testing.T) { }, Err: test.dialError, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: dialer, - } - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) env := jimmtest.ParseEnvironment(c, test.env) @@ -3742,20 +3722,20 @@ users: client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), OpenFGAClient: client, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ API: api, }, - } - ctx := context.Background() - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) + ctx := context.Background() + envDefinition := ` clouds: - name: test-cloud diff --git a/internal/jimm/relation_test.go b/internal/jimm/relation_test.go index 3938622af..68d652d97 100644 --- a/internal/jimm/relation_test.go +++ b/internal/jimm/relation_test.go @@ -29,15 +29,13 @@ func TestListRelationshipTuples(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) u := openfga.NewUser(&dbmodel.Identity{Name: "admin@canonical.com"}, ofgaClient) @@ -178,15 +176,13 @@ func TestListObjectRelations(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) u := openfga.NewUser(&dbmodel.Identity{Name: "admin@canonical.com"}, ofgaClient) diff --git a/internal/jimm/resource_test.go b/internal/jimm/resource_test.go index f36e6b815..db21aa3fa 100644 --- a/internal/jimm/resource_test.go +++ b/internal/jimm/resource_test.go @@ -24,15 +24,13 @@ func TestGetResources(t *testing.T) { c.Assert(err, qt.IsNil) now := time.Now().UTC().Round(time.Millisecond) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: ofgaClient, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) _, _, controller, model, applicationOffer, cloud, _, _ := createTestControllerEnvironment(ctx, c, j.Database) diff --git a/internal/jimm/service_account_test.go b/internal/jimm/service_account_test.go index db9508a3e..e7bbe0d4c 100644 --- a/internal/jimm/service_account_test.go +++ b/internal/jimm/service_account_test.go @@ -27,9 +27,12 @@ func TestAddServiceAccount(t *testing.T) { ctx := context.Background() client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ OpenFGAClient: client, - } + Database: &db.Database{ + DB: jimmtest.PostgresDB(c, func() time.Time { return now }), + }, + }) c.Assert(err, qt.IsNil) bob, err := dbmodel.NewIdentity("bob@canonical.com") @@ -68,18 +71,16 @@ func TestCopyServiceAccountCredential(t *testing.T) { return []jujuparams.UpdateCredentialModelResult{}, nil }, } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, Dialer: &jimmtest.Dialer{ API: api, }, OpenFGAClient: client, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) svcAccId, err := dbmodel.NewIdentity("39caae91-b914-41ae-83f8-c7b86ca5ad5a@serviceaccount") c.Assert(err, qt.IsNil) @@ -148,15 +149,13 @@ func TestCopyServiceAccountCredentialWithMissingCredential(t *testing.T) { ctx := context.Background() client, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: uuid.NewString(), - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, func() time.Time { return now }), }, OpenFGAClient: client, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) svcAccId, err := dbmodel.NewIdentity("39caae91-b914-41ae-83f8-c7b86ca5ad5a@serviceaccount") c.Assert(err, qt.IsNil) @@ -235,15 +234,16 @@ func TestGrantServiceAccountAccess(t *testing.T) { c.Run(test.about, func(c *qt.C) { ofgaClient, _, _, err := jimmtest.SetupTestOFGAClient(c.Name()) c.Assert(err, qt.IsNil) - pgDb := db.Database{ + pgDb := &db.Database{ DB: jimmtest.PostgresDB(c, nil), } err = pgDb.Migrate(context.Background(), false) c.Assert(err, qt.IsNil) - jimm := &jimm.JIMM{ + jimm, err := jimm.New(jimm.Parameters{ Database: pgDb, OpenFGAClient: ofgaClient, - } + }) + c.Assert(err, qt.IsNil) var u dbmodel.Identity u.SetTag(names.NewUserTag(test.clientID)) svcAccountIdentity := openfga.NewUser(&u, ofgaClient) diff --git a/internal/jimm/user_test.go b/internal/jimm/user_test.go index c4e7a8496..42a335f5b 100644 --- a/internal/jimm/user_test.go +++ b/internal/jimm/user_test.go @@ -27,13 +27,11 @@ func TestGetUser(t *testing.T) { DB: jimmtest.PostgresDB(c, time.Now), } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: "test", - Database: *db, + Database: db, OpenFGAClient: client, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) ofgaUser, err := j.GetUser(ctx, "bob@canonical.com.com") @@ -75,13 +73,11 @@ func TestUpdateUserLastLogin(t *testing.T) { DB: jimmtest.PostgresDB(c, func() time.Time { return now }), } - j := &jimm.JIMM{ + j, err := jimm.New(jimm.Parameters{ UUID: "test", - Database: *db, + Database: db, OpenFGAClient: client, - } - - err = j.Database.Migrate(ctx, false) + }) c.Assert(err, qt.IsNil) err = j.UpdateUserLastLogin(ctx, "bob@canonical.com.com") diff --git a/internal/jimm/watcher.go b/internal/jimm/watcher.go index a35a38271..e3a37b15c 100644 --- a/internal/jimm/watcher.go +++ b/internal/jimm/watcher.go @@ -28,7 +28,7 @@ type Publisher interface { // A Watcher watches juju controllers for changes to all models. type Watcher struct { // Database is the database used by the Watcher. - Database db.Database + Database *db.Database // Dialer is the API dialer JIMM uses to contact juju controllers. if // this is not configured all connection attempts will fail. diff --git a/internal/jimm/watcher_test.go b/internal/jimm/watcher_test.go index ba8b0c2a6..a6cf2478d 100644 --- a/internal/jimm/watcher_test.go +++ b/internal/jimm/watcher_test.go @@ -86,9 +86,9 @@ models: var watcherTests = []struct { name string - initDB func(*qt.C, db.Database) + initDB func(*qt.C, *db.Database) deltas [][]jujuparams.Delta - checkDB func(*qt.C, db.Database) + checkDB func(*qt.C, *db.Database) }{{ name: "AddMachine", deltas: [][]jujuparams.Delta{ @@ -104,7 +104,7 @@ var watcherTests = []struct { }}, nil, }, - checkDB: func(c *qt.C, db db.Database) { + checkDB: func(c *qt.C, db *db.Database) { ctx := context.Background() model := dbmodel.Model{ @@ -140,7 +140,7 @@ var watcherTests = []struct { }}, nil, }, - checkDB: func(c *qt.C, db db.Database) { + checkDB: func(c *qt.C, db *db.Database) { ctx := context.Background() model := dbmodel.Model{ @@ -176,7 +176,7 @@ var watcherTests = []struct { }}, nil, }, - checkDB: func(c *qt.C, db db.Database) { + checkDB: func(c *qt.C, db *db.Database) { ctx := context.Background() model := dbmodel.Model{ @@ -202,7 +202,7 @@ var watcherTests = []struct { }}, nil, }, - checkDB: func(c *qt.C, db db.Database) { + checkDB: func(c *qt.C, db *db.Database) { ctx := context.Background() model := dbmodel.Model{ @@ -233,7 +233,7 @@ var watcherTests = []struct { }}, nil, }, - checkDB: func(c *qt.C, db db.Database) { + checkDB: func(c *qt.C, db *db.Database) { ctx := context.Background() model := dbmodel.Model{ @@ -265,7 +265,7 @@ var watcherTests = []struct { }}, nil, }, - checkDB: func(c *qt.C, db db.Database) { + checkDB: func(c *qt.C, db *db.Database) { ctx := context.Background() model := dbmodel.Model{ @@ -292,7 +292,7 @@ var watcherTests = []struct { }}, nil, }, - checkDB: func(c *qt.C, db db.Database) { + checkDB: func(c *qt.C, db *db.Database) { ctx := context.Background() model := dbmodel.Model{ @@ -328,7 +328,7 @@ var watcherTests = []struct { }}, nil, }, - checkDB: func(c *qt.C, db db.Database) { + checkDB: func(c *qt.C, db *db.Database) { ctx := context.Background() model := dbmodel.Model{ @@ -376,7 +376,7 @@ var watcherTests = []struct { }}, nil, }, - checkDB: func(c *qt.C, db db.Database) { + checkDB: func(c *qt.C, db *db.Database) { ctx := context.Background() model := dbmodel.Model{ @@ -400,7 +400,7 @@ var watcherTests = []struct { }}, nil, }, - checkDB: func(c *qt.C, db db.Database) { + checkDB: func(c *qt.C, db *db.Database) { ctx := context.Background() model := dbmodel.Model{ @@ -424,7 +424,7 @@ var watcherTests = []struct { }}, nil, }, - checkDB: func(c *qt.C, db db.Database) { + checkDB: func(c *qt.C, db *db.Database) { ctx := context.Background() model := dbmodel.Model{ @@ -481,7 +481,7 @@ func TestWatcher(t *testing.T) { deltaProcessedChannel := make(chan bool, len(test.deltas)) w := jimm.NewWatcherWithDeltaProcessedChannel( - db.Database{ + &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, &jimmtest.Dialer{ @@ -645,7 +645,7 @@ func TestModelSummaryWatcher(t *testing.T) { w := &jimm.Watcher{ Pubsub: publisher, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ @@ -728,7 +728,7 @@ func TestWatcherSetsControllerUnavailable(t *testing.T) { controllerUnavailableChannel := make(chan error, 1) w := jimm.NewWatcherWithControllerUnavailableChan( - db.Database{ + &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, &jimmtest.Dialer{ @@ -774,7 +774,7 @@ func TestWatcherClearsControllerUnavailable(t *testing.T) { defer cancel() w := jimm.Watcher{ - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ @@ -846,7 +846,7 @@ func TestWatcherRemoveDyingModelsOnStartup(t *testing.T) { w := &jimm.Watcher{ Pubsub: &testPublisher{}, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: &jimmtest.Dialer{ @@ -935,7 +935,7 @@ func TestWatcherIgnoreDeltasForModelsFromIncorrectController(t *testing.T) { nextC := make(chan []jujuparams.Delta) w := &jimm.Watcher{ Pubsub: &testPublisher{}, - Database: db.Database{ + Database: &db.Database{ DB: jimmtest.PostgresDB(c, nil), }, Dialer: jimmtest.DialerMap{ diff --git a/internal/jujuapi/admin_test.go b/internal/jujuapi/admin_test.go index dce818039..692151a1b 100644 --- a/internal/jujuapi/admin_test.go +++ b/internal/jujuapi/admin_test.go @@ -58,7 +58,7 @@ func (s *adminSuite) SetUpTest(c *gc.C) { ClientSecret: "SwjDofnbDzJDm9iyfUhEp67FfUFMY8L4", Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, SessionTokenExpiry: time.Hour, - Store: &s.JIMM.Database, + Store: s.JIMM.Database, SessionStore: sessionStore, SessionCookieMaxAge: 60, JWTSessionKey: "test-secret", @@ -124,7 +124,7 @@ func testBrowserLogin(c *gc.C, s *adminSuite, username, password, expectedEmail, defer sessionStore.Close() cookie, err := jimmtest.RunBrowserLogin( - &s.JIMM.Database, + s.JIMM.Database, sessionStore, username, password, diff --git a/internal/jujuapi/websocket.go b/internal/jujuapi/websocket.go index 7da197c96..cf8f278d8 100644 --- a/internal/jujuapi/websocket.go +++ b/internal/jujuapi/websocket.go @@ -172,7 +172,7 @@ func modelInfoFromPath(path string) (uuid string, finalPath string, err error) { // We act as a proxier, handling auth on requests before forwarding the // requests to the appropriate Juju controller. func (s apiProxier) ServeWS(ctx context.Context, clientConn *websocket.Conn) { - jwtGenerator := jimm.NewJWTGenerator(&s.jimm.Database, s.jimm, s.jimm.JWTService) + jwtGenerator := jimm.NewJWTGenerator(s.jimm.Database, s.jimm, s.jimm.JWTService) connectionFunc := controllerConnectionFunc(s, &jwtGenerator) zapctx.Debug(ctx, "Starting proxier") auditLogger := s.jimm.AddAuditLogEntry diff --git a/internal/testutils/jimmtest/env.go b/internal/testutils/jimmtest/env.go index 65b00e8e2..52c0f315e 100644 --- a/internal/testutils/jimmtest/env.go +++ b/internal/testutils/jimmtest/env.go @@ -132,7 +132,7 @@ func (e *Environment) User(name string) *User { } // addUserRelations adds permissions the user should have. -func (u User) addUserRelations(c *qt.C, jimmTag names.ControllerTag, db db.Database, client *openfga.OFGAClient) { +func (u User) addUserRelations(c *qt.C, jimmTag names.ControllerTag, db *db.Database, client *openfga.OFGAClient) { if u.ControllerAccess == "superuser" { dbUser := u.DBObject(c, db) u := openfga.NewUser(&dbUser, client) @@ -142,7 +142,7 @@ func (u User) addUserRelations(c *qt.C, jimmTag names.ControllerTag, db db.Datab } // addCloudRelations adds permissions the cloud should have and adds permissions for users to the cloud. -func (cl Cloud) addCloudRelations(c *qt.C, db db.Database, client *openfga.OFGAClient) { +func (cl Cloud) addCloudRelations(c *qt.C, db *db.Database, client *openfga.OFGAClient) { for _, u := range cl.Users { dbUser := cl.env.User(u.User).DBObject(c, db) var relation openfga.Relation @@ -163,7 +163,7 @@ func (cl Cloud) addCloudRelations(c *qt.C, db db.Database, client *openfga.OFGAC } // addModelRelations adds permissions the model should have and adds permissions for users to the model. -func (m Model) addModelRelations(c *qt.C, db db.Database, client *openfga.OFGAClient) { +func (m Model) addModelRelations(c *qt.C, db *db.Database, client *openfga.OFGAClient) { owner := openfga.NewUser(&m.dbo.Owner, client) err := owner.SetModelAccess(context.Background(), m.dbo.ResourceTag(), ofganames.AdministratorRelation) c.Assert(err, qt.IsNil) @@ -207,7 +207,7 @@ func (ctl Controller) addControllerRelations(c *qt.C, client *openfga.OFGAClient c.Assert(err, qt.IsNil) } -func (e *Environment) addJIMMRelations(c *qt.C, jimmTag names.ControllerTag, db db.Database, client *openfga.OFGAClient) { +func (e *Environment) addJIMMRelations(c *qt.C, jimmTag names.ControllerTag, db *db.Database, client *openfga.OFGAClient) { for _, user := range e.Users { user.addUserRelations(c, jimmTag, db, client) } @@ -226,13 +226,13 @@ func (e *Environment) addJIMMRelations(c *qt.C, jimmTag names.ControllerTag, db } } -func (e *Environment) PopulateDBAndPermissions(c *qt.C, jimmTag names.ControllerTag, db db.Database, client *openfga.OFGAClient) { +func (e *Environment) PopulateDBAndPermissions(c *qt.C, jimmTag names.ControllerTag, db *db.Database, client *openfga.OFGAClient) { e.PopulateDB(c, db) c.Assert(client, qt.IsNotNil) e.addJIMMRelations(c, jimmTag, db, client) } -func (e *Environment) PopulateDB(c Tester, db db.Database) { +func (e *Environment) PopulateDB(c Tester, db *db.Database) { for i := range e.Users { e.Users[i].env = e e.Users[i].DBObject(c, db) @@ -279,7 +279,7 @@ type ApplicationOffer struct { dbo dbmodel.ApplicationOffer } -func (cd *ApplicationOffer) DBObject(c Tester, db db.Database) dbmodel.ApplicationOffer { +func (cd *ApplicationOffer) DBObject(c Tester, db *db.Database) dbmodel.ApplicationOffer { if cd.dbo.ID != 0 { return cd.dbo } @@ -307,7 +307,7 @@ type UserDefaults struct { dbo dbmodel.IdentityModelDefaults } -func (cd *UserDefaults) DBObject(c Tester, db db.Database) dbmodel.IdentityModelDefaults { +func (cd *UserDefaults) DBObject(c Tester, db *db.Database) dbmodel.IdentityModelDefaults { if cd.dbo.ID != 0 { return cd.dbo } @@ -334,7 +334,7 @@ type CloudDefaults struct { dbo dbmodel.CloudDefaults } -func (cd *CloudDefaults) DBObject(c Tester, db db.Database) dbmodel.CloudDefaults { +func (cd *CloudDefaults) DBObject(c Tester, db *db.Database) dbmodel.CloudDefaults { if cd.dbo.ID != 0 { return cd.dbo } @@ -372,7 +372,7 @@ type CloudRegion struct { // DBObject returns a database object for the specified cloud, suitable // for adding to the database. -func (cl *Cloud) DBObject(c Tester, db db.Database) dbmodel.Cloud { +func (cl *Cloud) DBObject(c Tester, db *db.Database) dbmodel.Cloud { if cl.dbo.ID != 0 { return cl.dbo } @@ -407,7 +407,7 @@ type CloudCredential struct { dbo dbmodel.CloudCredential } -func (cc *CloudCredential) DBObject(c Tester, db db.Database) dbmodel.CloudCredential { +func (cc *CloudCredential) DBObject(c Tester, db *db.Database) dbmodel.CloudCredential { if cc.dbo.ID != 0 { return cc.dbo } @@ -443,7 +443,7 @@ type Controller struct { dbo dbmodel.Controller } -func (ctl *Controller) DBObject(c Tester, db db.Database) dbmodel.Controller { +func (ctl *Controller) DBObject(c Tester, db *db.Database) dbmodel.Controller { if ctl.dbo.ID != 0 { return ctl.dbo } @@ -505,7 +505,7 @@ type Model struct { dbo dbmodel.Model } -func (m *Model) DBObject(c Tester, db db.Database) dbmodel.Model { +func (m *Model) DBObject(c Tester, db *db.Database) dbmodel.Model { if m.dbo.ID != 0 { return m.dbo } @@ -556,7 +556,7 @@ type User struct { dbo dbmodel.Identity } -func (u *User) DBObject(c Tester, db db.Database) dbmodel.Identity { +func (u *User) DBObject(c Tester, db *db.Database) dbmodel.Identity { if u.dbo.ID != 0 { return u.dbo } diff --git a/internal/testutils/jimmtest/suite.go b/internal/testutils/jimmtest/suite.go index 332486d26..bd67cc113 100644 --- a/internal/testutils/jimmtest/suite.go +++ b/internal/testutils/jimmtest/suite.go @@ -23,7 +23,6 @@ import ( "github.com/canonical/jimm/v3/internal/dbmodel" "github.com/canonical/jimm/v3/internal/discharger" "github.com/canonical/jimm/v3/internal/jimm" - "github.com/canonical/jimm/v3/internal/jimm/role" "github.com/canonical/jimm/v3/internal/jimmhttp" "github.com/canonical/jimm/v3/internal/jimmjwx" "github.com/canonical/jimm/v3/internal/jujuclient" @@ -69,34 +68,31 @@ type JIMMSuite struct { func (s *JIMMSuite) SetUpTest(c *gc.C) { var err error + // Setup OpenFGA. s.OFGAClient, s.COFGAClient, s.COFGAParams, err = SetupTestOFGAClient(c.TestName()) c.Assert(err, gc.IsNil) pgdb, databaseName := PostgresDBWithDbName(GocheckTester{c}, nil) s.databaseName = databaseName - // Setup OpenFGA. - s.JIMM = &jimm.JIMM{ - Database: db.Database{ + + s.deviceFlowChan = make(chan string, 1) + authenticator := NewMockOAuthAuthenticator(c, s.deviceFlowChan) + + j, err := jimm.New(jimm.Parameters{ + Database: &db.Database{ DB: pgdb, }, - CredentialStore: NewInMemoryCredentialStore(), - Pubsub: &pubsub.Hub{MaxConcurrency: 10}, - UUID: ControllerUUID, - OpenFGAClient: s.OFGAClient, - } - roleManager, err := role.NewRoleManager(&s.JIMM.Database, s.OFGAClient) + CredentialStore: NewInMemoryCredentialStore(), + Pubsub: &pubsub.Hub{MaxConcurrency: 10}, + UUID: ControllerUUID, + OpenFGAClient: s.OFGAClient, + OAuthAuthenticator: &authenticator, + }) c.Assert(err, gc.IsNil) - s.JIMM.RoleManager = roleManager + s.JIMM = j ctx, cancel := context.WithCancel(context.Background()) s.cancel = cancel - s.deviceFlowChan = make(chan string, 1) - authenticator := NewMockOAuthAuthenticator(c, s.deviceFlowChan) - s.JIMM.OAuthAuthenticator = &authenticator - - err = s.JIMM.Database.Migrate(ctx, false) - c.Assert(err, gc.Equals, nil) - alice, err := dbmodel.NewIdentity("alice@canonical.com") c.Assert(err, gc.IsNil) alice.LastLogin = db.Now() @@ -172,7 +168,7 @@ func (s *JIMMSuite) setupMacaroonDischarger(c *gc.C) *discharger.MacaroonDischar PrivateKey: "ly/dzsI9Nt/4JxUILQeAX79qZ4mygDiuYGqc2ZEiDEc=", PublicKey: "izcYsQy3TePp6bLjqOo3IRPFvkQd2IKtyODGqC6SdFk=", } - macaroonDischarger, err := discharger.NewMacaroonDischarger(cfg, &s.JIMM.Database, s.JIMM.OpenFGAClient) + macaroonDischarger, err := discharger.NewMacaroonDischarger(cfg, s.JIMM.Database, s.JIMM.OpenFGAClient) c.Assert(err, gc.IsNil) return macaroonDischarger }