Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,4 +269,5 @@ Code reviews are required for all submissions via GitHub pull requests.
- when creating PR message, keep it high-level, what functionality was added, don't add info about testing, no icons, no info about how the message was generated.
- app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts is a special case that we don't want to upgrade, so if it upgrades, put it back to main
- when creating a commit or PR message, NEVER add co-authored by or generated by Claude code
- if you modify a schema, remember to run `make migration_sync`
- any call to authorization Enforce done from the biz or svc layer must be done using biz.AuthzUseCase
- if you modify a schema, remember to run `make migration_sync`
20 changes: 15 additions & 5 deletions app/controlplane/cmd/wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func wireApp(*conf.Bootstrap, credentials.ReaderWriter, log.Logger, sdk.Availabl
wire.FieldsOf(new(*conf.Bootstrap), "Server", "Auth", "Data", "CasServer", "ReferrerSharedIndex", "Onboarding", "PrometheusIntegration", "PolicyProviders", "NatsServer", "FederatedAuthentication"),
wire.FieldsOf(new(*conf.Data), "Database"),
dispatcher.New,
authz.NewInMemoryEnforcer,
authz.NewCasbinEnforcer,
policies.NewRegistry,
newApp,
newProtoValidator,
Expand All @@ -65,13 +65,23 @@ func wireApp(*conf.Bootstrap, credentials.ReaderWriter, log.Logger, sdk.Availabl
newAuthAllowList,
newJWTConfig,
authzConfig,
authzUseCaseConfig,
biz.NewIndexConfig,
),
)
}

func authzConfig(conf *conf.Bootstrap) *authz.Config {
return &authz.Config{RolesMap: authz.RolesMap, RestrictOrgCreation: conf.RestrictOrgCreation}
func authzConfig() *authz.Config {
return &authz.Config{RolesMap: authz.RolesMap}
}

func authzUseCaseConfig(conf *conf.Bootstrap, casbinEnforcer *authz.CasbinEnforcer, apiTokenRepo biz.APITokenRepo, logger log.Logger) *biz.AuthzUseCaseConfig {
return &biz.AuthzUseCaseConfig{
CasbinEnforcer: casbinEnforcer,
APITokenRepo: apiTokenRepo,
RestrictOrgCreation: conf.RestrictOrgCreation,
Logger: logger,
}
}

func newJWTConfig(conf *conf.Auth) *biz.APITokenJWTConfig {
Expand All @@ -96,10 +106,10 @@ func newPolicyProviderConfig(in []*conf.PolicyProvider) []*policies.NewRegistryC
return out
}

func serviceOpts(l log.Logger, enforcer *authz.Enforcer, pUC *biz.ProjectUseCase, gUC *biz.GroupUseCase) []service.NewOpt {
func serviceOpts(l log.Logger, authzUC *biz.AuthzUseCase, pUC *biz.ProjectUseCase, gUC *biz.GroupUseCase) []service.NewOpt {
return []service.NewOpt{
service.WithLogger(l),
service.WithEnforcer(enforcer),
service.WithEnforcer(authzUC),
service.WithProjectUseCase(pUC),
service.WithGroupUseCase(gUC),
}
Expand Down
44 changes: 27 additions & 17 deletions app/controlplane/cmd/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions app/controlplane/configs/config.devel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ prometheus_integration:
- org_name: "development"

# Policy providers configuration
# policy_providers:
# - name: chainloop
# default: true
# url: http://localhost:8002/v1
policy_providers:
- name: chainloop
default: true
url: http://localhost:8002/v1

enable_profiler: true
# federated_authentication:
Expand Down
5 changes: 2 additions & 3 deletions app/controlplane/internal/server/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1"
"github.com/chainloop-dev/chainloop/app/controlplane/internal/sentrycontext"
"github.com/chainloop-dev/chainloop/app/controlplane/internal/usercontext/attjwtmiddleware"
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/authz"
authzMiddleware "github.com/chainloop-dev/chainloop/app/controlplane/pkg/authz/middleware"
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz"
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/jwt/user"
Expand All @@ -51,6 +50,7 @@ import (

type Opts struct {
// UseCases
AuthzUseCase *biz.AuthzUseCase
UserUseCase *biz.UserUseCase
RobotAccountUseCase *biz.RobotAccountUseCase
CASBackendUseCase *biz.CASBackendUseCase
Expand Down Expand Up @@ -91,7 +91,6 @@ type Opts struct {
FederatedConfig *conf.FederatedAuthentication
BootstrapConfig *conf.Bootstrap
Credentials credentials.ReaderWriter
Enforcer *authz.Enforcer
Validator *protovalidate.Validator
}

Expand Down Expand Up @@ -198,7 +197,7 @@ func craftMiddleware(opts *Opts) []middleware.Middleware {
// 2.d- Set its organization
usercontext.WithCurrentOrganizationMiddleware(opts.UserUseCase, logHelper),
// 3 - Check user/token authorization
authzMiddleware.WithAuthzMiddleware(opts.Enforcer, logHelper),
authzMiddleware.WithAuthzMiddleware(opts.AuthzUseCase, logHelper),
).Match(requireAllButOrganizationOperationsMatcher()).Build(),
// Store all memberships in the context
usercontext.WithCurrentMembershipsMiddleware(opts.MembershipUseCase),
Expand Down
10 changes: 5 additions & 5 deletions app/controlplane/internal/service/cascredential.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright 2023 The Chainloop Authors.
// Copyright 2023-2025 The Chainloop Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -34,18 +34,18 @@ type CASCredentialsService struct {
casUC *biz.CASCredentialsUseCase
casBackendUC *biz.CASBackendUseCase
casMappingUC *biz.CASMappingUseCase
authz *authz.Enforcer
authzUC *biz.AuthzUseCase
}

func NewCASCredentialsService(casUC *biz.CASCredentialsUseCase, casmUC *biz.CASMappingUseCase, casBUC *biz.CASBackendUseCase, authz *authz.Enforcer, opts ...NewOpt) *CASCredentialsService {
func NewCASCredentialsService(casUC *biz.CASCredentialsUseCase, casmUC *biz.CASMappingUseCase, casBUC *biz.CASBackendUseCase, authzUC *biz.AuthzUseCase, opts ...NewOpt) *CASCredentialsService {
return &CASCredentialsService{
service: newService(opts...),
casUC: casUC,
// we use the casMappingUC to find the backend to download from
casMappingUC: casmUC,
// we use the casBackendUC to find the default upload backend
casBackendUC: casBUC,
authz: authz,
authzUC: authzUC,
}
}

Expand Down Expand Up @@ -79,7 +79,7 @@ func (s *CASCredentialsService) Get(ctx context.Context, req *pb.CASCredentialsS
}

// Enforce required role
if ok, err := s.authz.Enforce(currentAuthzSubject, policyToCheck); err != nil {
if ok, err := s.authzUC.Enforce(ctx, currentAuthzSubject, policyToCheck); err != nil {
return nil, handleUseCaseErr(err, s.log)
} else if !ok {
return nil, errors.Forbidden("forbidden", "not allowed to perform this operation")
Expand Down
2 changes: 1 addition & 1 deletion app/controlplane/internal/service/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ func (g *GroupService) userHasPermissionOnGroupMembershipsWithPolicy(ctx context
m := entities.CurrentMembership(ctx)
for _, rm := range m.Resources {
if rm.ResourceType == authz.ResourceTypeGroup && rm.ResourceID == resolvedGroupID {
pass, err := g.enforcer.Enforce(string(rm.Role), policy)
pass, err := g.authz.Enforce(ctx, string(rm.Role), policy)
if err != nil {
return handleUseCaseErr(err, g.log)
}
Expand Down
4 changes: 2 additions & 2 deletions app/controlplane/internal/service/organization.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func (s *OrganizationService) UpdateMembership(ctx context.Context, req *pb.Orga

func (s *OrganizationService) canCreateOrganization(ctx context.Context) (bool, error) {
// Restricted org creation is disabled, allow creation
if !s.enforcer.RestrictOrgCreation {
if !s.authz.RestrictOrgCreation {
return true, nil
}

Expand All @@ -222,7 +222,7 @@ func (s *OrganizationService) canCreateOrganization(ctx context.Context) (bool,
continue
}

pass, err := s.enforcer.Enforce(string(rm.Role), authz.PolicyOrganizationCreate)
pass, err := s.authz.Enforce(ctx, string(rm.Role), authz.PolicyOrganizationCreate)
if err != nil {
return false, handleUseCaseErr(err, s.log)
}
Expand Down
10 changes: 5 additions & 5 deletions app/controlplane/internal/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func newService(opts ...NewOpt) *service {

type service struct {
log *log.Helper
enforcer *authz.Enforcer
authz *biz.AuthzUseCase
projectUseCase *biz.ProjectUseCase
groupUseCase *biz.GroupUseCase
}
Expand All @@ -146,9 +146,9 @@ func WithLogger(logger log.Logger) NewOpt {
}
}

func WithEnforcer(enforcer *authz.Enforcer) NewOpt {
func WithEnforcer(authzUC *biz.AuthzUseCase) NewOpt {
return func(s *service) {
s.enforcer = enforcer
s.authz = authzUC
}
}

Expand Down Expand Up @@ -231,7 +231,7 @@ func (s *service) authorizeResource(ctx context.Context, op *authz.Policy, resou
// Try to enforce the policy with each matching role
// If any role passes, authorize the request
for _, rm := range matchingResources {
pass, err := s.enforcer.Enforce(string(rm.Role), op)
pass, err := s.authz.Enforce(ctx, string(rm.Role), op)
if err != nil {
return handleUseCaseErr(err, s.log)
}
Expand Down Expand Up @@ -289,7 +289,7 @@ func (s *service) userCanCreateProject(ctx context.Context) error {
}

orgRole := usercontext.CurrentAuthzSubject(ctx)
pass, err := s.enforcer.Enforce(orgRole, authz.PolicyProjectCreate)
pass, err := s.authz.Enforce(ctx, orgRole, authz.PolicyProjectCreate)
if err != nil {
return handleUseCaseErr(err, s.log)
}
Expand Down
12 changes: 6 additions & 6 deletions app/controlplane/pkg/authz/authz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestDoSync(t *testing.T) {
}

// load custom policies
err := doSync(e, &Config{RolesMap: policiesM})
err := syncRBACRoles(e, &Config{RolesMap: policiesM})
assert.NoError(t, err)
got, err := e.GetPolicy()
assert.NoError(t, err)
Expand All @@ -92,7 +92,7 @@ func TestDoSync(t *testing.T) {
},
}

err = doSync(e, &Config{RolesMap: policiesM})
err = syncRBACRoles(e, &Config{RolesMap: policiesM})
assert.NoError(t, err)
got, err = e.GetPolicy()
assert.NoError(t, err)
Expand All @@ -105,7 +105,7 @@ func TestDoSync(t *testing.T) {
},
}

err = doSync(e, &Config{RolesMap: policiesM})
err = syncRBACRoles(e, &Config{RolesMap: policiesM})
assert.NoError(t, err)
got, err = e.GetPolicy()
assert.NoError(t, err)
Expand All @@ -117,7 +117,7 @@ func TestDoSync(t *testing.T) {
PolicyAttachedIntegrationDetach,
},
}
err = doSync(e, &Config{RolesMap: policiesM})
err = syncRBACRoles(e, &Config{RolesMap: policiesM})
assert.NoError(t, err)
got, err = e.GetPolicy()
assert.NoError(t, err)
Expand All @@ -129,13 +129,13 @@ func TestDoSync(t *testing.T) {
assert.Equal(t, "delete", got[0][2])
}

func testEnforcer(t *testing.T) (*Enforcer, io.Closer) {
func testEnforcer(t *testing.T) (*CasbinEnforcer, io.Closer) {
f, err := os.CreateTemp(t.TempDir(), "policy*.csv")
if err != nil {
require.FailNow(t, err.Error())
}

enforcer, err := NewFiletypeEnforcer(f.Name(), &Config{})
enforcer, err := NewCasbinEnforcer(&Config{})
require.NoError(t, err)
return enforcer, f
}
Loading
Loading