github.com/argoproj/argo-cd/v3@v3.2.1/server/repocreds/repocreds.go (about) 1 package repocreds 2 3 import ( 4 "context" 5 "reflect" 6 7 "github.com/argoproj/argo-cd/v3/util/argo" 8 9 "google.golang.org/grpc/codes" 10 "google.golang.org/grpc/status" 11 12 repocredspkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/repocreds" 13 appsv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 14 "github.com/argoproj/argo-cd/v3/util/db" 15 "github.com/argoproj/argo-cd/v3/util/rbac" 16 ) 17 18 // Server provides a Repository service 19 type Server struct { 20 db db.ArgoDB 21 enf *rbac.Enforcer 22 } 23 24 // NewServer returns a new instance of the Repository service 25 func NewServer( 26 db db.ArgoDB, 27 enf *rbac.Enforcer, 28 ) *Server { 29 return &Server{ 30 db: db, 31 enf: enf, 32 } 33 } 34 35 // ListRepositoryCredentials returns a list of all configured repository credential sets 36 func (s *Server) ListRepositoryCredentials(ctx context.Context, _ *repocredspkg.RepoCredsQuery) (*appsv1.RepoCredsList, error) { 37 urls, err := s.db.ListRepositoryCredentials(ctx) 38 if err != nil { 39 return nil, err 40 } 41 items := make([]appsv1.RepoCreds, 0) 42 for _, url := range urls { 43 if s.enf.Enforce(ctx.Value("claims"), rbac.ResourceRepositories, rbac.ActionGet, url) { 44 repo, err := s.db.GetRepositoryCredentials(ctx, url) 45 if err != nil { 46 return nil, err 47 } 48 if repo != nil { 49 items = append(items, appsv1.RepoCreds{ 50 URL: url, 51 Username: repo.Username, 52 }) 53 } 54 } 55 } 56 return &appsv1.RepoCredsList{Items: items}, nil 57 } 58 59 // ListWriteRepositoryCredentials returns a list of all configured repository credential sets 60 func (s *Server) ListWriteRepositoryCredentials(ctx context.Context, _ *repocredspkg.RepoCredsQuery) (*appsv1.RepoCredsList, error) { 61 urls, err := s.db.ListRepositoryCredentials(ctx) 62 if err != nil { 63 return nil, err 64 } 65 items := make([]appsv1.RepoCreds, 0) 66 for _, url := range urls { 67 if s.enf.Enforce(ctx.Value("claims"), rbac.ResourceWriteRepositories, rbac.ActionGet, url) { 68 repo, err := s.db.GetWriteRepositoryCredentials(ctx, url) 69 if err != nil { 70 return nil, err 71 } 72 if repo != nil && repo.Password != "" { 73 items = append(items, appsv1.RepoCreds{ 74 URL: url, 75 Username: repo.Username, 76 }) 77 } 78 } 79 } 80 return &appsv1.RepoCredsList{Items: items}, nil 81 } 82 83 // CreateRepositoryCredentials creates a new credential set in the configuration 84 func (s *Server) CreateRepositoryCredentials(ctx context.Context, q *repocredspkg.RepoCredsCreateRequest) (*appsv1.RepoCreds, error) { 85 if q.Creds == nil { 86 return nil, status.Errorf(codes.InvalidArgument, "missing payload in request") 87 } 88 if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceRepositories, rbac.ActionCreate, q.Creds.URL); err != nil { 89 return nil, err 90 } 91 92 r := q.Creds 93 94 if r.URL == "" { 95 return nil, status.Errorf(codes.InvalidArgument, "must specify URL") 96 } 97 98 _, err := s.db.CreateRepositoryCredentials(ctx, r) 99 if status.Convert(err).Code() == codes.AlreadyExists { 100 // act idempotent if existing spec matches new spec 101 existing, getErr := s.db.GetRepositoryCredentials(ctx, r.URL) 102 if getErr != nil { 103 return nil, status.Errorf(codes.Internal, "unable to check existing repository credentials details: %v", getErr) 104 } 105 106 switch { 107 case reflect.DeepEqual(existing, r): 108 err = nil 109 case q.Upsert: 110 return s.UpdateRepositoryCredentials(ctx, &repocredspkg.RepoCredsUpdateRequest{Creds: r}) 111 default: 112 return nil, status.Error(codes.InvalidArgument, argo.GenerateSpecIsDifferentErrorMessage("repository credentials", existing, r)) 113 } 114 } 115 return &appsv1.RepoCreds{URL: r.URL}, err 116 } 117 118 // CreateWriteRepositoryCredentials creates a new credential set in the configuration 119 func (s *Server) CreateWriteRepositoryCredentials(ctx context.Context, q *repocredspkg.RepoCredsCreateRequest) (*appsv1.RepoCreds, error) { 120 if q.Creds == nil { 121 return nil, status.Errorf(codes.InvalidArgument, "missing payload in request") 122 } 123 if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceWriteRepositories, rbac.ActionCreate, q.Creds.URL); err != nil { 124 return nil, err 125 } 126 127 r := q.Creds 128 129 if r.URL == "" { 130 return nil, status.Errorf(codes.InvalidArgument, "must specify URL") 131 } 132 133 _, err := s.db.CreateWriteRepositoryCredentials(ctx, r) 134 if status.Convert(err).Code() == codes.AlreadyExists { 135 // act idempotent if existing spec matches new spec 136 existing, getErr := s.db.GetWriteRepositoryCredentials(ctx, r.URL) 137 if getErr != nil { 138 return nil, status.Errorf(codes.Internal, "unable to check existing repository credentials details: %v", getErr) 139 } 140 141 switch { 142 case reflect.DeepEqual(existing, r): 143 err = nil 144 case q.Upsert: 145 return s.UpdateWriteRepositoryCredentials(ctx, &repocredspkg.RepoCredsUpdateRequest{Creds: r}) 146 default: 147 return nil, status.Error(codes.InvalidArgument, argo.GenerateSpecIsDifferentErrorMessage("repository credentials", existing, r)) 148 } 149 } 150 return &appsv1.RepoCreds{URL: r.URL}, err 151 } 152 153 // UpdateRepositoryCredentials updates a repository credential set 154 func (s *Server) UpdateRepositoryCredentials(ctx context.Context, q *repocredspkg.RepoCredsUpdateRequest) (*appsv1.RepoCreds, error) { 155 if q.Creds == nil { 156 return nil, status.Errorf(codes.InvalidArgument, "missing payload in request") 157 } 158 if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceRepositories, rbac.ActionUpdate, q.Creds.URL); err != nil { 159 return nil, err 160 } 161 _, err := s.db.UpdateRepositoryCredentials(ctx, q.Creds) 162 return &appsv1.RepoCreds{URL: q.Creds.URL}, err 163 } 164 165 // UpdateWriteRepositoryCredentials updates a repository credential set 166 func (s *Server) UpdateWriteRepositoryCredentials(ctx context.Context, q *repocredspkg.RepoCredsUpdateRequest) (*appsv1.RepoCreds, error) { 167 if q.Creds == nil { 168 return nil, status.Errorf(codes.InvalidArgument, "missing payload in request") 169 } 170 if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceWriteRepositories, rbac.ActionUpdate, q.Creds.URL); err != nil { 171 return nil, err 172 } 173 _, err := s.db.UpdateWriteRepositoryCredentials(ctx, q.Creds) 174 return &appsv1.RepoCreds{URL: q.Creds.URL}, err 175 } 176 177 // DeleteRepositoryCredentials removes a credential set from the configuration 178 func (s *Server) DeleteRepositoryCredentials(ctx context.Context, q *repocredspkg.RepoCredsDeleteRequest) (*repocredspkg.RepoCredsResponse, error) { 179 if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceRepositories, rbac.ActionDelete, q.Url); err != nil { 180 return nil, err 181 } 182 183 err := s.db.DeleteRepositoryCredentials(ctx, q.Url) 184 return &repocredspkg.RepoCredsResponse{}, err 185 } 186 187 // DeleteWriteRepositoryCredentials removes a credential set from the configuration 188 func (s *Server) DeleteWriteRepositoryCredentials(ctx context.Context, q *repocredspkg.RepoCredsDeleteRequest) (*repocredspkg.RepoCredsResponse, error) { 189 if err := s.enf.EnforceErr(ctx.Value("claims"), rbac.ResourceWriteRepositories, rbac.ActionDelete, q.Url); err != nil { 190 return nil, err 191 } 192 193 err := s.db.DeleteWriteRepositoryCredentials(ctx, q.Url) 194 return &repocredspkg.RepoCredsResponse{}, err 195 }