• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

goto / shield / 10787256047

10 Sep 2024 06:47AM UTC coverage: 51.953% (+0.01%) from 51.943%
10787256047

Pull #91

github

FemiNoviaLina
fix: core function name
Pull Request #91: feat: list resource of a user

66 of 143 new or added lines in 8 files covered. (46.15%)

1 existing line in 1 file now uncovered.

6809 of 13106 relevant lines covered (51.95%)

11.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/cmd/serve.go
1
package cmd
2

3
import (
4
        "context"
5
        "errors"
6
        "fmt"
7
        "io"
8
        "net/http"
9
        "os"
10
        "os/signal"
11
        "syscall"
12
        "time"
13

14
        _ "github.com/authzed/authzed-go/proto/authzed/api/v0"
15
        _ "github.com/jackc/pgx/v4/stdlib"
16
        "github.com/newrelic/go-agent/v3/newrelic"
17
        "go.opentelemetry.io/otel"
18
        "go.uber.org/zap"
19

20
        "github.com/goto/shield/config"
21
        "github.com/goto/shield/core/action"
22
        "github.com/goto/shield/core/activity"
23
        "github.com/goto/shield/core/group"
24
        "github.com/goto/shield/core/namespace"
25
        "github.com/goto/shield/core/organization"
26
        "github.com/goto/shield/core/policy"
27
        "github.com/goto/shield/core/project"
28
        "github.com/goto/shield/core/relation"
29
        "github.com/goto/shield/core/resource"
30
        "github.com/goto/shield/core/role"
31
        "github.com/goto/shield/core/servicedata"
32
        "github.com/goto/shield/core/user"
33
        "github.com/goto/shield/internal/adapter"
34
        "github.com/goto/shield/internal/api"
35
        "github.com/goto/shield/internal/schema"
36
        "github.com/goto/shield/internal/server"
37
        "github.com/goto/shield/internal/store/blob"
38
        "github.com/goto/shield/internal/store/inmemory"
39
        "github.com/goto/shield/internal/store/postgres"
40
        "github.com/goto/shield/internal/store/spicedb"
41
        "github.com/goto/shield/pkg/db"
42

43
        "github.com/goto/salt/log"
44
        "github.com/goto/salt/telemetry"
45
        "github.com/pkg/profile"
46
        "google.golang.org/grpc/codes"
47
)
48

49
var ruleCacheRefreshDelay = time.Minute * 2
50

51
func StartServer(logger *log.Zap, cfg *config.Shield) error {
×
52
        if profiling := os.Getenv("SHIELD_PROFILE"); profiling == "true" || profiling == "1" {
×
53
                defer profile.Start(profile.CPUProfile, profile.ProfilePath("."), profile.NoShutdownHook).Stop()
×
54
        }
×
55

56
        // @TODO: need to inject custom logger wrapper over zap into ctx to use it internally
57
        ctx, cancelFunc := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
×
58
        defer cancelFunc()
×
59

×
60
        cleanUpTelemetry, err := telemetry.Init(ctx, cfg.Telemetry, logger)
×
61
        if err != nil {
×
62
                return err
×
63
        }
×
64

65
        defer cleanUpTelemetry()
×
66

×
67
        dbClient, err := setupDB(cfg.DB, logger)
×
68
        if err != nil {
×
69
                return err
×
70
        }
×
71
        defer func() {
×
72
                logger.Info("cleaning up db")
×
73
                dbClient.Close()
×
74
        }()
×
75

76
        // load resource config
77
        if cfg.App.ResourcesConfigPath == "" {
×
78
                return errors.New("resource config path cannot be left empty")
×
79
        }
×
80

81
        resourceBlobFS, err := blob.NewStore(ctx, cfg.App.ResourcesConfigPath, cfg.App.ResourcesConfigPathSecret)
×
82
        if err != nil {
×
83
                return err
×
84
        }
×
85
        resourceBlobRepository := blob.NewResourcesRepository(logger, resourceBlobFS)
×
86
        if err := resourceBlobRepository.InitCache(ctx, ruleCacheRefreshDelay); err != nil {
×
87
                return err
×
88
        }
×
89
        defer func() {
×
90
                logger.Info("cleaning up resource blob")
×
91
                defer resourceBlobRepository.Close()
×
92
        }()
×
93

94
        spiceDBClient, err := spicedb.New(cfg.SpiceDB, logger)
×
95
        if err != nil {
×
96
                return err
×
97
        }
×
98

99
        nrApp, err := setupNewRelic(cfg.NewRelic, logger)
×
100
        if err != nil {
×
101
                return err
×
102
        }
×
103

104
        schemaMigrationConfig := schema.NewSchemaMigrationConfig(cfg.App.DefaultSystemEmail, cfg.App.ServiceData.BootstrapEnabled)
×
105

×
106
        appConfig := activity.AppConfig{Version: config.Version}
×
107
        var activityRepository activity.Repository
×
108
        switch cfg.Log.Activity.Sink {
×
109
        case activity.SinkTypeDB:
×
110
                activityRepository = postgres.NewActivityRepository(dbClient)
×
111
        case activity.SinkTypeStdout:
×
112
                stdoutLogger, err := zap.NewStdLogAt(logger.GetInternalZapLogger().Desugar(), logger.GetInternalZapLogger().Level())
×
113
                if err != nil {
×
114
                        return err
×
115
                }
×
116
                activityRepository = activity.NewStdoutRepository(stdoutLogger.Writer())
×
117
        default:
×
118
                activityRepository = activity.NewStdoutRepository(io.Discard)
×
119
        }
120
        activityService := activity.NewService(appConfig, activityRepository)
×
121

×
122
        userRepository := postgres.NewUserRepository(dbClient)
×
123
        userService := user.NewService(logger, userRepository, activityService)
×
124

×
125
        actionRepository := postgres.NewActionRepository(dbClient)
×
126
        actionService := action.NewService(logger, actionRepository, userService, activityService)
×
127

×
128
        roleRepository := postgres.NewRoleRepository(dbClient)
×
129
        roleService := role.NewService(logger, roleRepository, userService, activityService)
×
130

×
131
        policyPGRepository := postgres.NewPolicyRepository(dbClient)
×
132
        policySpiceRepository := spicedb.NewPolicyRepository(spiceDBClient)
×
133
        policyService := policy.NewService(logger, policyPGRepository, userService, activityService)
×
134

×
135
        namespaceRepository := postgres.NewNamespaceRepository(dbClient)
×
136
        namespaceService := namespace.NewService(logger, namespaceRepository, userService, activityService)
×
137

×
138
        s := schema.NewSchemaMigrationService(
×
139
                blob.NewSchemaConfigRepository(resourceBlobFS),
×
140
                namespaceService,
×
141
                roleService,
×
142
                actionService,
×
143
                policyService,
×
144
                policySpiceRepository,
×
145
                userRepository,
×
146
                schemaMigrationConfig,
×
147
        )
×
148

×
149
        err = s.RunMigrations(ctx)
×
150
        if err != nil {
×
151
                return err
×
152
        }
×
153

154
        deps, err := BuildAPIDependencies(ctx, logger, activityRepository, resourceBlobRepository, dbClient, spiceDBClient, cfg)
×
155
        if err != nil {
×
156
                return err
×
157
        }
×
158

159
        // serving proxies
160
        cbs, cps, err := serveProxies(ctx, logger, cfg.App.IdentityProxyHeader, cfg.App.UserIDHeader, cfg.Proxy, deps.ResourceService, deps.RelationService, deps.UserService, deps.GroupService, deps.ProjectService, deps.RelationAdapter)
×
161
        if err != nil {
×
162
                return err
×
163
        }
×
164
        defer func() {
×
165
                // clean up stage
×
166
                logger.Info("cleaning up rules proxy blob")
×
167
                for _, f := range cbs {
×
168
                        if err := f(); err != nil {
×
169
                                logger.Warn("error occurred during shutdown rules proxy blob storages", "err", err)
×
170
                        }
×
171
                }
172

173
                logger.Info("cleaning up proxies")
×
174
                for _, f := range cps {
×
175
                        shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), time.Second*20)
×
176
                        if err := f(shutdownCtx); err != nil {
×
177
                                shutdownCancel()
×
178
                                logger.Warn("error occurred during shutdown proxies", "err", err)
×
179
                                continue
×
180
                        }
181
                        shutdownCancel()
×
182
                }
183
        }()
184

185
        // serving server
186
        return server.Serve(ctx, logger, cfg.App, nrApp, deps)
×
187
}
188

189
func BuildAPIDependencies(
190
        ctx context.Context,
191
        logger log.Logger,
192
        activityRepository activity.Repository,
193
        resourceBlobRepository *blob.ResourcesRepository,
194
        dbc *db.Client,
195
        sdb *spicedb.SpiceDB,
196
        cfg *config.Shield,
197
) (api.Deps, error) {
×
198
        cache, err := inmemory.NewCache(cfg.App.CacheConfig)
×
199
        if err != nil {
×
200
                return api.Deps{}, err
×
201
        }
×
202

203
        if err = cache.MonitorCache(otel.Meter("github.com/goto/shield/internal/store/inmemory")); err != nil {
×
204
                return api.Deps{}, err
×
205
        }
×
206

207
        appConfig := activity.AppConfig{Version: config.Version}
×
208
        activityService := activity.NewService(appConfig, activityRepository)
×
209

×
210
        userRepository := postgres.NewUserRepository(dbc)
×
211
        userService := user.NewService(logger, userRepository, activityService)
×
212

×
213
        actionRepository := postgres.NewActionRepository(dbc)
×
214
        actionService := action.NewService(logger, actionRepository, userService, activityService)
×
215

×
216
        namespaceRepository := postgres.NewNamespaceRepository(dbc)
×
217
        namespaceService := namespace.NewService(logger, namespaceRepository, userService, activityService)
×
218

×
219
        roleRepository := postgres.NewRoleRepository(dbc)
×
220
        roleService := role.NewService(logger, roleRepository, userService, activityService)
×
221

×
222
        relationPGRepository := postgres.NewRelationRepository(dbc)
×
223
        relationSpiceRepository := spicedb.NewRelationRepository(sdb)
×
224
        relationService := relation.NewService(logger, relationPGRepository, relationSpiceRepository, userService, activityService)
×
225

×
226
        groupRepository := postgres.NewGroupRepository(dbc)
×
227
        cachedGroupRepository := inmemory.NewCachedGroupRepository(cache, groupRepository)
×
228
        groupService := group.NewService(logger, groupRepository, cachedGroupRepository, relationService, userService, activityService)
×
229

×
230
        organizationRepository := postgres.NewOrganizationRepository(dbc)
×
231
        organizationService := organization.NewService(logger, organizationRepository, relationService, userService, activityService)
×
232

×
233
        projectRepository := postgres.NewProjectRepository(dbc)
×
234
        projectService := project.NewService(logger, projectRepository, relationService, userService, activityService)
×
235

×
236
        policyPGRepository := postgres.NewPolicyRepository(dbc)
×
237
        policyService := policy.NewService(logger, policyPGRepository, userService, activityService)
×
238

×
239
        resourcePGRepository := postgres.NewResourceRepository(dbc)
×
240
        resourceService := resource.NewService(
×
NEW
241
                logger, resourcePGRepository, resourceBlobRepository, relationService, userService, projectService, organizationService, groupService, policyService, namespaceService, activityService)
×
242

×
243
        serviceDataRepository := postgres.NewServiceDataRepository(dbc)
×
244
        serviceDataService := servicedata.NewService(logger, serviceDataRepository, resourceService, relationService, projectService, userService, activityService)
×
245

×
246
        relationAdapter := adapter.NewRelation(groupService, userService, relationService, roleService)
×
247

×
248
        dependencies := api.Deps{
×
249
                OrgService:         organizationService,
×
250
                UserService:        userService,
×
251
                ProjectService:     projectService,
×
252
                GroupService:       groupService,
×
253
                RelationService:    relationService,
×
254
                ResourceService:    resourceService,
×
255
                RoleService:        roleService,
×
256
                PolicyService:      policyService,
×
257
                ActionService:      actionService,
×
258
                NamespaceService:   namespaceService,
×
259
                RelationAdapter:    relationAdapter,
×
260
                ActivityService:    activityService,
×
261
                ServiceDataService: serviceDataService,
×
262
        }
×
263
        return dependencies, nil
×
264
}
265

266
func setupNewRelic(cfg config.NewRelic, logger log.Logger) (*newrelic.Application, error) {
×
267
        nrApp, err := newrelic.NewApplication(func(nrCfg *newrelic.Config) {
×
268
                nrCfg.Enabled = cfg.Enabled
×
269
                nrCfg.AppName = cfg.AppName
×
270
                nrCfg.ErrorCollector.IgnoreStatusCodes = []int{
×
271
                        http.StatusNotFound,
×
272
                        http.StatusUnauthorized,
×
273
                        int(codes.Unauthenticated),
×
274
                        int(codes.PermissionDenied),
×
275
                        int(codes.InvalidArgument),
×
276
                        int(codes.AlreadyExists),
×
277
                }
×
278
                nrCfg.License = cfg.License
×
279
        })
×
280
        if err != nil {
×
281
                return nil, errors.New("failed to load Newrelic Application")
×
282
        }
×
283
        return nrApp, nil
×
284
}
285

286
func setupDB(cfg db.Config, logger log.Logger) (dbc *db.Client, err error) {
×
287
        // prefer use pgx instead of lib/pq for postgres to catch pg error
×
288
        if cfg.Driver == "postgres" {
×
289
                cfg.Driver = "pgx"
×
290
        }
×
291
        dbc, err = db.New(cfg)
×
292
        if err != nil {
×
293
                err = fmt.Errorf("failed to setup db: %w", err)
×
294
                return
×
295
        }
×
296

297
        return
×
298
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc