Files
upstream-corteza/server/pkg/envoy/store/system.go
upstream-mirror 7e385fc126
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
2026-09-18 01:22:23 +05:00

765 lines
15 KiB
Go

package store
import (
"context"
"strings"
composeTypes "github.com/cortezaproject/corteza/server/compose/types"
"github.com/cortezaproject/corteza/server/pkg/envoy"
"github.com/cortezaproject/corteza/server/pkg/envoy/resource"
pkgid "github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rbac"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
"github.com/spf13/cast"
)
type (
roleFilter types.RoleFilter
userFilter types.UserFilter
templateFilter types.TemplateFilter
applicationFilter types.ApplicationFilter
apiGwRouteFilter types.ApigwRouteFilter
reportFilter types.ReportFilter
settingFilter types.SettingsFilter
rbacFilter struct {
rbac.RuleFilter
// This will help us determine what rules for what resources we are able to export
resourceID map[uint64]bool
strict bool
}
resourceTranslationFilter types.ResourceTranslationFilter
systemDecoder struct {
resourceID []uint64
ux *userIndex
}
)
func newSystemDecoder(ux *userIndex) *systemDecoder {
return &systemDecoder{
resourceID: make([]uint64, 0, 200),
ux: ux,
}
}
func (d *systemDecoder) decodeRoles(ctx context.Context, s store.Storer, ff []*roleFilter) *auxRsp {
mm := make([]envoy.Marshaller, 0, 100)
if ff == nil {
return &auxRsp{
mm: mm,
}
}
var nn types.RoleSet
var fn types.RoleFilter
var err error
for _, f := range ff {
aux := *f
if aux.Limit == 0 {
aux.Limit = 1000
}
for {
nn, fn, err = s.SearchRoles(ctx, types.RoleFilter(aux))
if err != nil {
return &auxRsp{
err: err,
}
}
for _, n := range nn {
mm = append(mm, newRole(n))
d.resourceID = append(d.resourceID, n.ID)
}
if fn.NextPage != nil {
aux.PageCursor = fn.NextPage
} else {
break
}
}
}
return &auxRsp{
mm: mm,
}
}
func (d *systemDecoder) decodeUsers(ctx context.Context, s store.Storer, ff []*userFilter) *auxRsp {
mm := make([]envoy.Marshaller, 0, 100)
if ff == nil {
return &auxRsp{
mm: mm,
}
}
var nn types.UserSet
var fn types.UserFilter
var err error
for _, f := range ff {
aux := *f
if aux.Limit == 0 {
aux.Limit = 1000
}
for {
nn, fn, err = s.SearchUsers(ctx, types.UserFilter(aux))
if err != nil {
return &auxRsp{
err: err,
}
}
for _, n := range nn {
mm = append(mm, newUser(n))
d.resourceID = append(d.resourceID, n.ID)
}
if fn.NextPage != nil {
aux.PageCursor = fn.NextPage
} else {
break
}
}
}
return &auxRsp{
mm: mm,
}
}
func (d *systemDecoder) decodeTemplates(ctx context.Context, s store.Storer, ff []*templateFilter) *auxRsp {
mm := make([]envoy.Marshaller, 0, 100)
if ff == nil {
return &auxRsp{
mm: mm,
}
}
var nn types.TemplateSet
var fn types.TemplateFilter
var err error
for _, f := range ff {
aux := *f
if aux.Limit == 0 {
aux.Limit = 1000
}
for {
nn, fn, err = s.SearchTemplates(ctx, types.TemplateFilter(aux))
if err != nil {
return &auxRsp{
err: err,
}
}
for _, n := range nn {
mm = append(mm, newTemplate(n))
d.resourceID = append(d.resourceID, n.ID)
}
if fn.NextPage != nil {
aux.PageCursor = fn.NextPage
} else {
break
}
}
}
return &auxRsp{
mm: mm,
}
}
func (d *systemDecoder) decodeAPIGWRoutes(ctx context.Context, s store.Storer, ff []*apiGwRouteFilter) *auxRsp {
mm := make([]envoy.Marshaller, 0, 100)
if ff == nil {
return &auxRsp{
mm: mm,
}
}
var nn types.ApigwRouteSet
var fn types.ApigwRouteFilter
var err error
for _, f := range ff {
aux := *f
if aux.Limit == 0 {
aux.Limit = 1000
}
for {
nn, fn, err = s.SearchApigwRoutes(ctx, types.ApigwRouteFilter(aux))
if err != nil {
return &auxRsp{
err: err,
}
}
// filters
for _, n := range nn {
gwf, _, err := s.SearchApigwFilters(ctx, types.ApigwFilterFilter{RouteID: n.ID})
if err != nil {
return &auxRsp{
err: err,
}
}
mm = append(mm, newAPIGateway(n, gwf, d.ux))
d.resourceID = append(d.resourceID, n.ID)
}
if fn.NextPage != nil {
aux.PageCursor = fn.NextPage
} else {
break
}
}
}
return &auxRsp{
mm: mm,
}
}
func (d *systemDecoder) decodeReports(ctx context.Context, s store.Storer, ff []*reportFilter) *auxRsp {
mm := make([]envoy.Marshaller, 0, 100)
if ff == nil {
return &auxRsp{
mm: mm,
}
}
var nn types.ReportSet
var fn types.ReportFilter
var err error
for _, f := range ff {
aux := *f
if aux.Limit == 0 {
aux.Limit = 1000
}
for {
nn, fn, err = s.SearchReports(ctx, types.ReportFilter(aux))
if err != nil {
return &auxRsp{
err: err,
}
}
for _, n := range nn {
mm = append(mm, newReport(n, d.ux))
d.resourceID = append(d.resourceID, n.ID)
}
if fn.NextPage != nil {
aux.PageCursor = fn.NextPage
} else {
break
}
}
}
return &auxRsp{
mm: mm,
}
}
func (d *systemDecoder) decodeApplications(ctx context.Context, s store.Storer, ff []*applicationFilter) *auxRsp {
mm := make([]envoy.Marshaller, 0, 100)
if ff == nil {
return &auxRsp{
mm: mm,
}
}
var nn types.ApplicationSet
var fn types.ApplicationFilter
var err error
for _, f := range ff {
aux := *f
if aux.Limit == 0 {
aux.Limit = 1000
}
for {
nn, fn, err = s.SearchApplications(ctx, types.ApplicationFilter(aux))
if err != nil {
return &auxRsp{
err: err,
}
}
for _, n := range nn {
// Index users
err = d.ux.add(
ctx,
n.OwnerID,
)
mm = append(mm, newApplication(n, d.ux))
d.resourceID = append(d.resourceID, n.ID)
}
if fn.NextPage != nil {
aux.PageCursor = fn.NextPage
} else {
break
}
}
}
return &auxRsp{
mm: mm,
}
}
func (d *systemDecoder) decodeSettings(ctx context.Context, s store.Storer, ff []*settingFilter) *auxRsp {
mm := make([]envoy.Marshaller, 0, 100)
if ff == nil {
return &auxRsp{
mm: mm,
}
}
var nn types.SettingValueSet
var err error
for _, f := range ff {
aux := *f
for {
nn, _, err = store.SearchSettingValues(ctx, s, types.SettingsFilter(aux))
if err != nil {
return &auxRsp{
err: err,
}
}
for _, n := range nn {
// Index users
err = d.ux.add(
ctx,
n.OwnedBy,
n.UpdatedBy,
)
mm = append(mm, newSetting(n, d.ux))
}
// mm = append(mm, NewSettings(nn))
break
}
}
return &auxRsp{
mm: mm,
}
}
func (d *systemDecoder) decodeRbac(ctx context.Context, s store.Storer, ff []*rbacFilter) *auxRsp {
mm := make([]envoy.Marshaller, 0, 100)
if ff == nil {
return &auxRsp{
mm: mm,
}
}
var nn rbac.RuleSet
var err error
c := func(r *resource.Ref, f *rbacFilter, path ...*resource.Ref) (bool, error) {
if r == nil {
return true, nil
}
// the first identifier is the most specific .. the ID
id, err := cast.ToUint64E(r.Identifiers.First())
if err != nil {
return false, err
}
if r.ResourceType == composeTypes.ModuleFieldResourceType {
id, err = cast.ToUint64E(path[1].Identifiers.First())
if err != nil {
return false, err
}
}
return f.resourceID[id], nil
}
for _, f := range ff {
aux := *f
for {
nn, _, err = s.SearchRbacRules(ctx, rbac.RuleFilter(aux.RuleFilter))
if err != nil {
return &auxRsp{
err: err,
}
}
for _, n := range nn {
r, err := newRbacRule(n)
rt := strings.Split(r.refRbacResource, "/")[0]
if err != nil {
return &auxRsp{
err: err,
}
}
// somesort of a generic rule; no specifc resource
// @todo check for pp inclusion!!
if r.refRbacRes == nil && len(r.refPathRes) == 0 {
mm = append(mm, r)
} else {
// Check the resource ref and the path refs for validity.
// ComposeRecords are fetched in chunks so this check is not valid here.
if rt != composeTypes.RecordResourceType {
if ok, err := c(r.refRbacRes, f, r.refPathRes...); err != nil {
return &auxRsp{
err: err,
}
} else if !ok {
continue
}
}
for _, p := range r.refPathRes {
if ok, err := c(p, f); err != nil {
return &auxRsp{
err: err,
}
} else if !ok {
continue
}
}
mm = append(mm, r)
}
}
break
}
}
return &auxRsp{
mm: mm,
}
}
func (d *systemDecoder) decodeResourceTranslation(ctx context.Context, s store.Storer, ff []*resourceTranslationFilter) *auxRsp {
mm := make([]envoy.Marshaller, 0, 100)
if ff == nil {
return &auxRsp{
mm: mm,
}
}
var (
resMap = make(map[string]*resourceTranslation)
nn types.ResourceTranslationSet
fn types.ResourceTranslationFilter
err error
)
for _, f := range ff {
aux := *f
if aux.Limit == 0 {
aux.Limit = 1000
}
for {
nn, fn, err = s.SearchResourceTranslations(ctx, types.ResourceTranslationFilter(aux))
if err != nil {
return &auxRsp{
err: err,
}
}
for _, n := range nn {
if _, ok := resMap[n.Resource]; !ok {
resMap[n.Resource], err = newResourceTranslation(types.ResourceTranslationSet{n})
if err != nil {
return &auxRsp{
err: err,
}
}
// parse the resource wo we can define relations/check if we can unmarshal it
_, ref, pp, err := resource.ParseResourceTranslation(n.Resource)
resMap[n.Resource].refLocaleRes = ref
resMap[n.Resource].refPathRes = pp
if err != nil {
return &auxRsp{
err: err,
}
}
continue
}
resMap[n.Resource].locales = append(resMap[n.Resource].locales, n)
}
if fn.NextPage != nil {
aux.PageCursor = fn.NextPage
} else {
break
}
break
}
}
for _, lr := range resMap {
mm = append(mm, lr)
}
return &auxRsp{
mm: mm,
}
}
func (df *DecodeFilter) systemFromResource(rr ...string) *DecodeFilter {
for _, r := range rr {
if !strings.HasPrefix(r, "system") {
continue
}
id := ""
if strings.Count(r, ":") == 2 && !strings.HasSuffix(r, "*") {
// There is an identifier
aux := strings.Split(r, ":")
id = aux[len(aux)-1]
r = strings.Join(aux[:len(aux)-1], ":")
}
switch strings.ToLower(r) {
case "system:role":
df = df.Roles(&types.RoleFilter{
Query: id,
})
case "system:user":
df = df.Users(&types.UserFilter{
Query: id,
AllKinds: true,
})
case "system:template":
df = df.Templates(&types.TemplateFilter{
Handle: id,
})
templateID, err := cast.ToUint64E(id)
if err == nil && templateID > 0 {
df = df.Templates(&types.TemplateFilter{
TemplateID: pkgid.Strings(templateID),
})
}
case "system:apigw-route":
df = df.APIGWRoutes(&types.ApigwRouteFilter{
Route: id,
})
case "system:report":
df = df.Reports(&types.ReportFilter{
Handle: id,
})
reportID, err := cast.ToUint64E(id)
if err == nil && reportID > 0 {
df = df.Reports(&types.ReportFilter{
ReportID: pkgid.Strings(reportID),
})
}
case "system:application":
df = df.Applications(&types.ApplicationFilter{
Query: id,
})
case "system:setting":
df = df.Settings(&types.SettingsFilter{})
case "system:rbac":
df = df.Rbac(&rbac.RuleFilter{})
case "system:resource-translation":
df = df.Rbac(&rbac.RuleFilter{})
}
}
return df
}
func (df *DecodeFilter) systemFromRef(rr ...*resource.Ref) *DecodeFilter {
for _, r := range rr {
if strings.Index(r.ResourceType, "system") < 0 {
continue
}
switch r.ResourceType {
case types.RoleResourceType:
for _, i := range r.Identifiers.StringSlice() {
df = df.Roles(&types.RoleFilter{
Query: i,
})
}
case types.UserResourceType:
for _, i := range r.Identifiers.StringSlice() {
df = df.Users(&types.UserFilter{
Query: i,
AllKinds: true,
})
}
case types.TemplateResourceType:
for _, i := range r.Identifiers.StringSlice() {
df = df.Templates(&types.TemplateFilter{
Handle: i,
})
templateID, err := cast.ToUint64E(i)
if err == nil && templateID > 0 {
df = df.Templates(&types.TemplateFilter{
TemplateID: pkgid.Strings(templateID),
})
}
}
case types.ApplicationResourceType:
for _, i := range r.Identifiers.StringSlice() {
df = df.Applications(&types.ApplicationFilter{
Query: i,
})
}
}
}
return df
}
// Roles adds a new RoleFilter
func (df *DecodeFilter) Roles(f *types.RoleFilter) *DecodeFilter {
if df.roles == nil {
df.roles = make([]*roleFilter, 0, 1)
}
df.roles = append(df.roles, (*roleFilter)(f))
return df
}
// Users adds a new UserFilter
func (df *DecodeFilter) Users(f *types.UserFilter) *DecodeFilter {
if df.users == nil {
df.users = make([]*userFilter, 0, 1)
}
df.users = append(df.users, (*userFilter)(f))
return df
}
// Templates adds a new TemplateFilter
func (df *DecodeFilter) Templates(f *types.TemplateFilter) *DecodeFilter {
if df.templates == nil {
df.templates = make([]*templateFilter, 0, 1)
}
df.templates = append(df.templates, (*templateFilter)(f))
return df
}
func (df *DecodeFilter) APIGWRoutes(f *types.ApigwRouteFilter) *DecodeFilter {
if df.apiGwRoutes == nil {
df.apiGwRoutes = make([]*apiGwRouteFilter, 0, 1)
}
df.apiGwRoutes = append(df.apiGwRoutes, (*apiGwRouteFilter)(f))
return df
}
func (df *DecodeFilter) Reports(f *types.ReportFilter) *DecodeFilter {
if df.reports == nil {
df.reports = make([]*reportFilter, 0, 1)
}
df.reports = append(df.reports, (*reportFilter)(f))
return df
}
// Applications adds a new ApplicationFilter
func (df *DecodeFilter) Applications(f *types.ApplicationFilter) *DecodeFilter {
if df.applications == nil {
df.applications = make([]*applicationFilter, 0, 1)
}
df.applications = append(df.applications, (*applicationFilter)(f))
return df
}
// Settings adds a new SettingsFilter
func (df *DecodeFilter) Settings(f *types.SettingsFilter) *DecodeFilter {
if df.settings == nil {
df.settings = make([]*settingFilter, 0, 1)
}
df.settings = append(df.settings, (*settingFilter)(f))
return df
}
// Rbac adds a new RuleFilter
func (df *DecodeFilter) Rbac(f *rbac.RuleFilter) *DecodeFilter {
if df.rbac == nil {
df.rbac = make([]*rbacFilter, 0, 1)
} else {
// There can only be a single rbac filter
// since it makes no sense to have multiple of
return df
}
df.rbac = append(df.rbac, &rbacFilter{RuleFilter: *f})
return df
}
// ResourceTranslation adds a new ResourceTranslationFilter
func (df *DecodeFilter) ResourceTranslation(f *types.ResourceTranslationFilter) *DecodeFilter {
if df.resourceTranslations == nil {
df.resourceTranslations = make([]*resourceTranslationFilter, 0, 1)
} else {
// There can only be a single resourceTranslations filter
// since it makes no sense to have multiple of
return df
}
df.resourceTranslations = append(df.resourceTranslations, (*resourceTranslationFilter)(f))
return df
}
func (df *DecodeFilter) RbacStrict(f *rbac.RuleFilter) *DecodeFilter {
if df.rbac == nil {
df.rbac = make([]*rbacFilter, 0, 1)
} else {
// There can only be a single rbac filter
// since it makes no sense to have multiple of
return df
}
df.rbac = append(df.rbac, &rbacFilter{RuleFilter: *f})
return df
}
// allowRbacResource adds a new resource identifier to supported resource rules
func (df *DecodeFilter) allowRbacResource(id ...uint64) {
if df.rbac == nil || len(df.rbac) == 0 {
return
}
rf := df.rbac[0]
if rf.resourceID == nil {
rf.resourceID = make(map[uint64]bool)
}
for _, i := range id {
rf.resourceID[i] = true
}
}