Skip to content

Commit

Permalink
Merge pull request #5980 from devtron-labs/release-candidate-v0.20.0
Browse files Browse the repository at this point in the history
misc: Release candidate v0.20.0
  • Loading branch information
vikramdevtron authored Oct 14, 2024
2 parents 8cd7ab0 + a846895 commit d52be33
Show file tree
Hide file tree
Showing 153 changed files with 5,179 additions and 2,017 deletions.
2 changes: 1 addition & 1 deletion Wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func InitializeApp() (*App, error) {
terminal.TerminalWireSet,
build.BuildWireSet,
deployment2.DeploymentWireSet,
argoApplication.ArgoApplicationWireSet,
argoApplication.ArgoApplicationWireSetFull,
fluxApplication.FluxApplicationWireSet,
eventProcessor.EventProcessorWireSet,
workflow3.WorkflowWireSet,
Expand Down
3 changes: 0 additions & 3 deletions api/appStore/AppStoreRouter.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,6 @@ func (router AppStoreRouterImpl) Init(configRouter *mux.Router) {
HandlerFunc(router.deployRestHandler.CheckAppExists).Methods("POST")
configRouter.Path("/group/install").
HandlerFunc(router.deployRestHandler.DeployBulk).Methods("POST")
configRouter.Path("/installed-app/detail").Queries("installed-app-id", "{installed-app-id}").Queries("env-id", "{env-id}").
HandlerFunc(router.deployRestHandler.FetchAppDetailsForInstalledApp).
Methods("GET")
configRouter.Path("/installed-app/delete/{installedAppId}/non-cascade").
HandlerFunc(router.deployRestHandler.DeleteArgoInstalledAppWithNonCascade).
Methods("DELETE")
Expand Down
99 changes: 4 additions & 95 deletions api/appStore/InstalledAppRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ import (
"github.com/devtron-labs/devtron/pkg/auth/authorisation/casbin"
"github.com/devtron-labs/devtron/pkg/auth/user"
"github.com/devtron-labs/devtron/pkg/cluster"
bean3 "github.com/devtron-labs/devtron/pkg/deployment/common/bean"
"github.com/devtron-labs/devtron/util"
"github.com/devtron-labs/devtron/util/argo"
"github.com/devtron-labs/devtron/util/rbac"
Expand All @@ -65,7 +64,6 @@ type InstalledAppRestHandler interface {
DeployBulk(w http.ResponseWriter, r *http.Request)
CheckAppExists(w http.ResponseWriter, r *http.Request)
DefaultComponentInstallation(w http.ResponseWriter, r *http.Request)
FetchAppDetailsForInstalledApp(w http.ResponseWriter, r *http.Request)
DeleteArgoInstalledAppWithNonCascade(w http.ResponseWriter, r *http.Request)
FetchAppDetailsForInstalledAppV2(w http.ResponseWriter, r *http.Request)
FetchResourceTree(w http.ResponseWriter, r *http.Request)
Expand Down Expand Up @@ -692,90 +690,6 @@ func (handler *InstalledAppRestHandlerImpl) checkNotesAuth(token string, appName
return ok
}

func (handler *InstalledAppRestHandlerImpl) FetchAppDetailsForInstalledApp(w http.ResponseWriter, r *http.Request) {
userId, err := handler.userAuthService.GetLoggedInUser(r)
if userId == 0 || err != nil {
common.WriteJsonResp(w, err, nil, http.StatusUnauthorized)
return
}

vars := mux.Vars(r)
installedAppId, err := strconv.Atoi(vars["installed-app-id"])
if err != nil {
handler.Logger.Errorw("request err, FetchAppDetailsForInstalledApp", "err", err, "installedAppId", installedAppId)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
token := r.Header.Get("token")
envId, err := strconv.Atoi(vars["env-id"])
if err != nil {
handler.Logger.Errorw("request err, FetchAppDetailsForInstalledApp", "err", err, "installedAppId", installedAppId, "envId", envId)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
handler.Logger.Infow("request payload, FetchAppDetailsForInstalledApp, app store", "installedAppId", installedAppId, "envId", envId)

installedApp, err := handler.installedAppService.GetInstalledAppById(installedAppId)
if err == pg.ErrNoRows {
common.WriteJsonResp(w, err, "App not found in database", http.StatusBadRequest)
return
}
if util3.IsExternalChartStoreApp(installedApp.App.DisplayName) {
//this is external app case where app_name is a unique identifier, and we want to fetch resource based on display_name
handler.installedAppService.ChangeAppNameToDisplayNameForInstalledApp(installedApp)
}

appDetail, err := handler.installedAppService.FindAppDetailsForAppstoreApplication(installedAppId, envId)
if err != nil {
handler.Logger.Errorw("service err, FetchAppDetailsForInstalledApp, app store", "err", err, "installedAppId", installedAppId, "envId", envId)
common.WriteJsonResp(w, err, nil, http.StatusInternalServerError)
return
}

//rbac block starts from here
object, object2 := handler.enforcerUtil.GetHelmObjectByAppNameAndEnvId(appDetail.AppName, appDetail.EnvironmentId)

var ok bool

if object2 == "" {
ok = handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, object)
} else {
ok = handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, object) || handler.enforcer.Enforce(token, casbin.ResourceHelmApp, casbin.ActionGet, object2)
}

if !ok {
common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden)
return
}
//rback block ends here
resourceTreeAndNotesContainer := bean2.AppDetailsContainer{}
resourceTreeAndNotesContainer.ResourceTree = map[string]interface{}{}

if len(installedApp.App.AppName) > 0 && len(installedApp.Environment.Name) > 0 {
err = handler.fetchResourceTree(w, r, &resourceTreeAndNotesContainer, *installedApp, appDetail.DeploymentConfig, "", "")
if appDetail.DeploymentAppType == util2.PIPELINE_DEPLOYMENT_TYPE_ACD {
apiError, ok := err.(*util2.ApiError)
if ok && apiError != nil {
if apiError.Code == constants.AppDetailResourceTreeNotFound && installedApp.DeploymentAppDeleteRequest == true {
// TODO refactoring: should be performed through nats
err = handler.appStoreDeploymentService.MarkGitOpsInstalledAppsDeletedIfArgoAppIsDeleted(installedAppId, envId)
appDeleteErr, appDeleteErrOk := err.(*util2.ApiError)
if appDeleteErrOk && appDeleteErr != nil {
handler.Logger.Errorw(appDeleteErr.InternalMessage)
return
}
}
}
} else if err != nil {
common.WriteJsonResp(w, fmt.Errorf("error in fetching resource tree"), nil, http.StatusInternalServerError)
return
}
}
appDetail.ResourceTree = resourceTreeAndNotesContainer.ResourceTree
appDetail.Notes = resourceTreeAndNotesContainer.Notes
common.WriteJsonResp(w, nil, appDetail, http.StatusOK)
}

func (handler *InstalledAppRestHandlerImpl) FetchAppDetailsForInstalledAppV2(w http.ResponseWriter, r *http.Request) {
userId, err := handler.userAuthService.GetLoggedInUser(r)
if userId == 0 || err != nil {
Expand Down Expand Up @@ -820,6 +734,8 @@ func (handler *InstalledAppRestHandlerImpl) FetchAppDetailsForInstalledAppV2(w h
}

func (handler *InstalledAppRestHandlerImpl) FetchResourceTree(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("token")
ctx := context.WithValue(r.Context(), "token", token)
userId, err := handler.userAuthService.GetLoggedInUser(r)
if userId == 0 || err != nil {
common.WriteJsonResp(w, err, nil, http.StatusUnauthorized)
Expand Down Expand Up @@ -853,7 +769,6 @@ func (handler *InstalledAppRestHandlerImpl) FetchResourceTree(w http.ResponseWri
common.WriteJsonResp(w, nil, nil, http.StatusOK)
return
}
token := r.Header.Get("token")
object, object2 := handler.enforcerUtil.GetHelmObjectByAppNameAndEnvId(installedApp.App.AppName, installedApp.EnvironmentId)
var ok bool
if object2 == "" {
Expand All @@ -876,7 +791,8 @@ func (handler *InstalledAppRestHandlerImpl) FetchResourceTree(w http.ResponseWri
resourceTreeAndNotesContainer.ResourceTree = map[string]interface{}{}

if len(installedApp.App.AppName) > 0 && len(installedApp.Environment.Name) > 0 {
err = handler.fetchResourceTree(w, r, &resourceTreeAndNotesContainer, *installedApp, appDetail.DeploymentConfig, appDetail.HelmReleaseInstallStatus, appDetail.Status)
cn, _ := w.(http.CloseNotifier)
err = handler.installedAppResourceService.FetchResourceTree(ctx, cn, &resourceTreeAndNotesContainer, *installedApp, appDetail.DeploymentConfig, appDetail.HelmReleaseInstallStatus, appDetail.Status)
if appDetail.DeploymentAppType == util2.PIPELINE_DEPLOYMENT_TYPE_ACD {
//resource tree has been fetched now prepare to sync application deployment status with this resource tree call
handler.syncDeploymentStatusWithResourceTreeCall(appDetail)
Expand Down Expand Up @@ -968,13 +884,6 @@ func (handler *InstalledAppRestHandlerImpl) FetchResourceTreeForACDApp(w http.Re
common.WriteJsonResp(w, err, appDetail, http.StatusOK)
}

func (handler *InstalledAppRestHandlerImpl) fetchResourceTree(w http.ResponseWriter, r *http.Request, resourceTreeAndNotesContainer *bean2.AppDetailsContainer, installedApp repository.InstalledApps, deploymentConfig *bean3.DeploymentConfig, helmReleaseInstallStatus string, status string) error {
ctx := r.Context()
cn, _ := w.(http.CloseNotifier)
err := handler.installedAppResourceService.FetchResourceTree(ctx, cn, resourceTreeAndNotesContainer, installedApp, deploymentConfig, helmReleaseInstallStatus, status)
return err
}

func (handler *InstalledAppRestHandlerImpl) fetchResourceTreeWithHibernateForACD(w http.ResponseWriter, r *http.Request, appDetail *bean2.AppDetailContainer) {
ctx := r.Context()
cn, _ := w.(http.CloseNotifier)
Expand Down
7 changes: 4 additions & 3 deletions api/appbean/AppDetail.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,10 @@ type Secret struct {
}

type ConfigMapSecretDataVolumeUsageConfig struct {
MountPath string `json:"mountPath"`
SubPath bool `json:"subPath"`
FilePermission string `json:"filePermission"`
MountPath string `json:"mountPath"`
SubPath bool `json:"subPath"`
FilePermission string `json:"filePermission"`
ESOSubPath []string `json:"esoSubPath"`
}

type ExternalSecret struct {
Expand Down
16 changes: 15 additions & 1 deletion api/argoApplication/wire_argoApplication.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,21 @@ import (
"github.com/google/wire"
)

var ArgoApplicationWireSet = wire.NewSet(
var ArgoApplicationWireSetFull = wire.NewSet(
read.NewArgoApplicationReadServiceImpl,
wire.Bind(new(read.ArgoApplicationReadService), new(*read.ArgoApplicationReadServiceImpl)),

argoApplication.NewArgoApplicationServiceExtendedServiceImpl,
wire.Bind(new(argoApplication.ArgoApplicationService), new(*argoApplication.ArgoApplicationServiceExtendedImpl)),

NewArgoApplicationRestHandlerImpl,
wire.Bind(new(ArgoApplicationRestHandler), new(*ArgoApplicationRestHandlerImpl)),

NewArgoApplicationRouterImpl,
wire.Bind(new(ArgoApplicationRouter), new(*ArgoApplicationRouterImpl)),
)

var ArgoApplicationWireSetEA = wire.NewSet(
read.NewArgoApplicationReadServiceImpl,
wire.Bind(new(read.ArgoApplicationReadService), new(*read.ArgoApplicationReadServiceImpl)),

Expand Down
56 changes: 30 additions & 26 deletions api/auth/user/UserRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1190,7 +1190,7 @@ func (handler UserRestHandlerImpl) checkRBACForUserCreate(token string, requestS
}

func (handler UserRestHandlerImpl) checkRBACForUserUpdate(token string, userInfo *bean.UserInfo, isUserAlreadySuperAdmin bool, eliminatedRoleFilters,
eliminatedGroupRoles []*repository.RoleModel) (isAuthorised bool, err error) {
eliminatedGroupRoles []*repository.RoleModel, mapOfExistingUserRoleGroup map[string]bool) (isAuthorised bool, err error) {
isActionUserSuperAdmin := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*")
requestSuperAdmin := userInfo.SuperAdmin
if (requestSuperAdmin || isUserAlreadySuperAdmin) && !isActionUserSuperAdmin {
Expand Down Expand Up @@ -1241,33 +1241,37 @@ func (handler UserRestHandlerImpl) checkRBACForUserUpdate(token string, userInfo
}
}
if len(roleGroups) > 0 { // auth check inside groups
groupRoles, err := handler.roleGroupService.FetchRolesForUserRoleGroups(roleGroups)
if err != nil && err != pg.ErrNoRows {
handler.logger.Errorw("service err, UpdateUser", "err", err, "payload", roleGroups)
return false, err
}
if len(groupRoles) > 0 {
for _, groupRole := range groupRoles {
switch {
case groupRole.Action == bean.ACTION_SUPERADMIN:
isAuthorised = isActionUserSuperAdmin
case groupRole.AccessType == bean.APP_ACCESS_TYPE_HELM || groupRole.Entity == bean2.EntityJobs:
isAuthorised = isActionUserSuperAdmin
case len(groupRole.Team) > 0:
isAuthorised = handler.enforcer.Enforce(token, casbin.ResourceUser, casbin.ActionCreate, groupRole.Team)
case groupRole.Entity == bean.CLUSTER_ENTITIY:
isAuthorised = handler.userCommonService.CheckRbacForClusterEntity(groupRole.Cluster, groupRole.Namespace, groupRole.Group, groupRole.Kind, groupRole.Resource, token, handler.CheckManagerAuth)
case groupRole.Entity == bean.CHART_GROUP_ENTITY:
isAuthorised = true
default:
isAuthorised = false
}
if !isAuthorised {
return false, nil
//filter out roleGroups (existing has to be ignore while checking rbac)
filteredRoleGroups := util2.FilterRoleGroupIfAlreadyPresent(roleGroups, mapOfExistingUserRoleGroup)
if len(filteredRoleGroups) > 0 {
groupRoles, err := handler.roleGroupService.FetchRolesForUserRoleGroups(roleGroups)
if err != nil && err != pg.ErrNoRows {
handler.logger.Errorw("service err, UpdateUser", "err", err, "filteredRoleGroups", filteredRoleGroups)
return false, err
}
if len(groupRoles) > 0 {
for _, groupRole := range groupRoles {
switch {
case groupRole.Action == bean.ACTION_SUPERADMIN:
isAuthorised = isActionUserSuperAdmin
case groupRole.AccessType == bean.APP_ACCESS_TYPE_HELM || groupRole.Entity == bean2.EntityJobs:
isAuthorised = isActionUserSuperAdmin
case len(groupRole.Team) > 0:
isAuthorised = handler.enforcer.Enforce(token, casbin.ResourceUser, casbin.ActionCreate, groupRole.Team)
case groupRole.Entity == bean.CLUSTER_ENTITIY:
isAuthorised = handler.userCommonService.CheckRbacForClusterEntity(groupRole.Cluster, groupRole.Namespace, groupRole.Group, groupRole.Kind, groupRole.Resource, token, handler.CheckManagerAuth)
case groupRole.Entity == bean.CHART_GROUP_ENTITY:
isAuthorised = true
default:
isAuthorised = false
}
if !isAuthorised {
return false, nil
}
}
} else {
isAuthorised = false
}
} else {
isAuthorised = false
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions api/auth/user/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,25 @@

package util

import (
"github.com/devtron-labs/devtron/api/bean"
"github.com/devtron-labs/devtron/pkg/auth/user/helper"
)

func IsGroupsPresent(groups []string) bool {
if len(groups) > 0 {
return true
}
return false
}

func FilterRoleGroupIfAlreadyPresent(roleGroups []bean.UserRoleGroup, mapOfExistingUserRoleGroup map[string]bool) []bean.UserRoleGroup {
finalRoleGroups := make([]bean.UserRoleGroup, 0, len(roleGroups))
for _, roleGrp := range roleGroups {
if _, ok := mapOfExistingUserRoleGroup[helper.GetCasbinNameFromRoleGroupName(roleGrp.RoleGroup.Name)]; !ok {
finalRoleGroups = append(finalRoleGroups, roleGrp)
}
}
return finalRoleGroups

}
3 changes: 2 additions & 1 deletion api/bean/ConfigMapAndSecret.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type ConfigSecretMap struct {
RoleARN string `json:"roleARN"`
SecretData json.RawMessage `json:"secretData,omitempty"`
SubPath bool `json:"subPath"`
ESOSubPath []string `json:"esoSubPath"`
FilePermission string `json:"filePermission"`
}

Expand All @@ -70,7 +71,7 @@ func (configSecretJson *ConfigSecretJson) SetReferencedSecrets(secrets []ConfigS
configSecretJson.Secrets = util.GetReferencedArray(secrets)
}

func (ConfigSecretRootJson) GetTransformedDataForSecretData(data string, mode util.SecretTransformMode) (string, error) {
func GetTransformedDataForSecretData(data string, mode util.SecretTransformMode) (string, error) {
secretsJson := ConfigSecretRootJson{}
err := json.Unmarshal([]byte(data), &secretsJson)
if err != nil {
Expand Down
17 changes: 9 additions & 8 deletions api/helm-app/service/HelmAppService.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"errors"
"fmt"
"github.com/devtron-labs/common-lib/utils/k8s"
"github.com/devtron-labs/common-lib/utils/k8s/commonBean"
"github.com/devtron-labs/devtron/api/helm-app/bean"
"github.com/devtron-labs/devtron/api/helm-app/gRPC"
"github.com/devtron-labs/devtron/api/helm-app/models"
Expand Down Expand Up @@ -234,15 +235,15 @@ func (impl *HelmAppServiceImpl) GetClusterConf(clusterId int) (*gRPC.ClusterConf
}
config := &gRPC.ClusterConfig{
ApiServerUrl: cluster.ServerUrl,
Token: cluster.Config[k8s.BearerToken],
Token: cluster.Config[commonBean.BearerToken],
ClusterId: int32(cluster.Id),
ClusterName: cluster.ClusterName,
InsecureSkipTLSVerify: cluster.InsecureSkipTLSVerify,
}
if cluster.InsecureSkipTLSVerify == false {
config.KeyData = cluster.Config[k8s.TlsKey]
config.CertData = cluster.Config[k8s.CertData]
config.CaData = cluster.Config[k8s.CertificateAuthorityData]
config.KeyData = cluster.Config[commonBean.TlsKey]
config.CertData = cluster.Config[commonBean.CertData]
config.CaData = cluster.Config[commonBean.CertificateAuthorityData]
}
return config, nil
}
Expand Down Expand Up @@ -1095,15 +1096,15 @@ func (impl *HelmAppServiceImpl) listApplications(ctx context.Context, clusterIds
for _, clusterDetail := range clusters {
config := &gRPC.ClusterConfig{
ApiServerUrl: clusterDetail.ServerUrl,
Token: clusterDetail.Config[k8s.BearerToken],
Token: clusterDetail.Config[commonBean.BearerToken],
ClusterId: int32(clusterDetail.Id),
ClusterName: clusterDetail.ClusterName,
InsecureSkipTLSVerify: clusterDetail.InsecureSkipTLSVerify,
}
if clusterDetail.InsecureSkipTLSVerify == false {
config.KeyData = clusterDetail.Config[k8s.TlsKey]
config.CertData = clusterDetail.Config[k8s.CertData]
config.CaData = clusterDetail.Config[k8s.CertificateAuthorityData]
config.KeyData = clusterDetail.Config[commonBean.TlsKey]
config.CertData = clusterDetail.Config[commonBean.CertData]
config.CaData = clusterDetail.Config[commonBean.CertificateAuthorityData]
}
req.Clusters = append(req.Clusters, config)
}
Expand Down
5 changes: 4 additions & 1 deletion api/restHandler/CoreAppRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ func (handler CoreAppRestHandlerImpl) buildAppConfigMaps(appId int, envId int, c
}
var dataObj map[string]interface{}
if data != nil {
err := json.Unmarshal([]byte(data), &dataObj)
err := json.Unmarshal(data, &dataObj)
if err != nil {
handler.logger.Errorw("service err, un-marshaling of data fail in config map", "err", err, "appId", appId)
return nil, err, http.StatusInternalServerError
Expand Down Expand Up @@ -1041,6 +1041,7 @@ func (handler CoreAppRestHandlerImpl) buildAppSecrets(appId int, envId int, secr
globalSecret.DataVolumeUsageConfig = &appBean.ConfigMapSecretDataVolumeUsageConfig{
SubPath: secret.SubPath,
FilePermission: secret.FilePermission,
ESOSubPath: secret.ESOSubPath,
}
considerGlobalDefaultData := envId > 0 && secret.Data == nil
if considerGlobalDefaultData {
Expand Down Expand Up @@ -1486,6 +1487,7 @@ func (handler CoreAppRestHandlerImpl) createGlobalSecrets(appId int, userId int3
secretData.MountPath = dataVolumeUsageConfig.MountPath
secretData.SubPath = dataVolumeUsageConfig.SubPath
secretData.FilePermission = dataVolumeUsageConfig.FilePermission
secretData.ESOSubPath = dataVolumeUsageConfig.ESOSubPath
}

if secret.IsExternal {
Expand Down Expand Up @@ -1989,6 +1991,7 @@ func (handler CoreAppRestHandlerImpl) createEnvSecret(appId int, userId int32, e
secretData.MountPath = secretOverrideDataVolumeUsageConfig.MountPath
secretData.SubPath = secretOverrideDataVolumeUsageConfig.SubPath
secretData.FilePermission = secretOverrideDataVolumeUsageConfig.FilePermission
secretData.ESOSubPath = secretOverrideDataVolumeUsageConfig.ESOSubPath
}
var secretDataRequest []*bean2.ConfigData
secretDataRequest = append(secretDataRequest, secretData)
Expand Down
Loading

0 comments on commit d52be33

Please sign in to comment.