snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
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
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
This commit is contained in:
339
server/system/envoy/yaml_encode.go
Normal file
339
server/system/envoy/yaml_encode.go
Normal file
@@ -0,0 +1,339 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza/server/pkg/y7s"
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type (
|
||||
// Wrapper to avoid constant type casting for role nodes
|
||||
rbacRuleWrap struct {
|
||||
node *envoyx.Node
|
||||
rule *rbac.Rule
|
||||
}
|
||||
|
||||
// Wrapper to keep role and rules together
|
||||
rbacRuleRoleWrap struct {
|
||||
rules []rbacRuleWrap
|
||||
roleNode *envoyx.Node
|
||||
role *types.Role
|
||||
}
|
||||
)
|
||||
|
||||
func (e YamlEncoder) encode(ctx context.Context, base *yaml.Node, p envoyx.EncodeParams, rt string, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
switch rt {
|
||||
case rbac.RuleResourceType:
|
||||
return e.encodeRbacRules(ctx, base, p, nodes, tt)
|
||||
case types.ResourceTranslationResourceType:
|
||||
return e.encodeResourceTranslations(ctx, base, p, nodes, tt)
|
||||
case types.SettingValueResourceType:
|
||||
return e.encodeSettingValues(ctx, base, p, nodes, tt)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeResourceTranslations(ctx context.Context, base *yaml.Node, p envoyx.EncodeParams, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
err = e.resolveRulePathDeps(ctx, tt, nodes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
byLang := make(map[string][]*envoyx.Node)
|
||||
|
||||
for _, n := range nodes {
|
||||
byLang[n.Resource.(*types.ResourceTranslation).Lang.String()] = append(byLang[n.Resource.(*types.ResourceTranslation).Lang.String()], n)
|
||||
}
|
||||
|
||||
out = base
|
||||
|
||||
var aux *yaml.Node
|
||||
for lang, nodes := range byLang {
|
||||
aux, err = e.encodeResourceTranslationsByResource(p, nodes, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddMap(out, lang, aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return y7s.MakeMap("locale", out)
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeResourceTranslationsByResource(p envoyx.EncodeParams, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
byResource := make(map[string][]*envoyx.Node)
|
||||
|
||||
for _, n := range nodes {
|
||||
byResource[n.Resource.(*types.ResourceTranslation).Resource] = append(byResource[n.Resource.(*types.ResourceTranslation).Resource], n)
|
||||
}
|
||||
|
||||
var aux *yaml.Node
|
||||
for resource, nodes := range byResource {
|
||||
aux, err = e.encodeResourceTranslationsKv(p, nodes, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddMap(out, resource, aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeResourceTranslationsKv(p envoyx.EncodeParams, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
out, _ = y7s.MakeMap()
|
||||
|
||||
for _, n := range nodes {
|
||||
rt := n.Resource.(*types.ResourceTranslation)
|
||||
out, err = y7s.AddMap(out, rt.K, rt.Message)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeRbacRules(ctx context.Context, base *yaml.Node, p envoyx.EncodeParams, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
err = e.resolveRulePathDeps(ctx, tt, nodes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Batch by access (allow, deny)
|
||||
allows := make([]rbacRuleWrap, 0, len(nodes))
|
||||
denies := make([]rbacRuleWrap, 0, len(nodes))
|
||||
for _, n := range nodes {
|
||||
r := n.Resource.(*rbac.Rule)
|
||||
if r.Access == rbac.Allow {
|
||||
allows = append(allows, rbacRuleWrap{
|
||||
node: n,
|
||||
rule: r,
|
||||
})
|
||||
} else {
|
||||
denies = append(denies, rbacRuleWrap{
|
||||
node: n,
|
||||
rule: r,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Encode allows
|
||||
var aux *yaml.Node
|
||||
aux, err = e.encodeRbacRulesByRole(p, allows, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
out = base
|
||||
out, err = y7s.AddMap(out, "allow", aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Encode denies
|
||||
aux, err = e.encodeRbacRulesByRole(p, denies, tt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
out, err = y7s.AddMap(out, "deny", aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeSettingValues(ctx context.Context, base *yaml.Node, p envoyx.EncodeParams, nodes envoyx.NodeSet, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
// Setting values don't have any refs
|
||||
|
||||
for _, n := range nodes {
|
||||
sv := n.Resource.(*types.SettingValue)
|
||||
base, err = y7s.AddMap(base, sv.Name, sv.Value)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return y7s.MakeMap("settings", base)
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeRbacRulesByRole(p envoyx.EncodeParams, rules []rbacRuleWrap, tt envoyx.Traverser) (out *yaml.Node, err error) {
|
||||
// Batch by role; make sure to keep the multiple identifier thing in mind
|
||||
byRole := make(map[string]rbacRuleRoleWrap)
|
||||
for _, r := range rules {
|
||||
role := r.node.References["RoleID"]
|
||||
aux := rbacRuleRoleWrap{}
|
||||
ok := false
|
||||
|
||||
// Check if an identifier already exists
|
||||
for _, ident := range role.Identifiers.Slice {
|
||||
aux, ok = byRole[ident]
|
||||
if ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If not, create a new entry and resolve the role
|
||||
if !ok {
|
||||
aux.roleNode = tt.ParentForRef(r.node, role)
|
||||
if aux.roleNode != nil {
|
||||
aux.role = aux.roleNode.Resource.(*types.Role)
|
||||
}
|
||||
}
|
||||
|
||||
// Add the rule to the batch and update potentially missing identifiers
|
||||
aux.rules = append(aux.rules, r)
|
||||
for _, ident := range role.Identifiers.Slice {
|
||||
byRole[ident] = aux
|
||||
}
|
||||
}
|
||||
|
||||
// Encode
|
||||
var aux *yaml.Node
|
||||
for _, r := range byRole {
|
||||
aux, err = e.encodeRbacRulesByResource(p, r.rules)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddMap(out,
|
||||
r.roleNode.Identifiers.FriendlyIdentifier(), aux,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeRbacRulesByResource(p envoyx.EncodeParams, rules []rbacRuleWrap) (out *yaml.Node, err error) {
|
||||
byResource := make(map[string][]rbacRuleWrap)
|
||||
|
||||
// Batch
|
||||
for _, r := range rules {
|
||||
byResource[r.rule.Resource] = append(byResource[r.rule.Resource], r)
|
||||
}
|
||||
|
||||
// Encode
|
||||
var aux *yaml.Node
|
||||
for resource, rules := range byResource {
|
||||
aux, err = e.encodeRbacRuleOperations(p, rules)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
out, err = y7s.AddMap(out, resource, aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeRbacRuleOperations(p envoyx.EncodeParams, rules []rbacRuleWrap) (out *yaml.Node, err error) {
|
||||
ops, _ := y7s.MakeSeq()
|
||||
|
||||
for _, r := range rules {
|
||||
ops, err = y7s.AddSeq(ops, r.rule.Operation)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return ops, nil
|
||||
}
|
||||
|
||||
func (e YamlEncoder) resolveRulePathDeps(ctx context.Context, tt envoyx.Traverser, nodes envoyx.NodeSet) (err error) {
|
||||
for _, n := range nodes {
|
||||
|
||||
var auxIdent string
|
||||
for fieldLabel, ref := range n.References {
|
||||
// Only resolve path refs; others are done later on
|
||||
if !strings.Contains(fieldLabel, "Path.") {
|
||||
continue
|
||||
}
|
||||
|
||||
auxIdent = safeParentIdentifier(tt, n, ref)
|
||||
if auxIdent == "" || auxIdent == "0" {
|
||||
continue
|
||||
}
|
||||
|
||||
err = n.Resource.SetValue(fieldLabel, 0, auxIdent)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeAuthClientSecurityC(ctx context.Context, p envoyx.EncodeParams, tt envoyx.Traverser, n *envoyx.Node, ac *types.AuthClient, sec *types.AuthClientSecurity) (_ any, err error) {
|
||||
sqPermittedRoles, err := e.encodeRoleSlice(n, tt, "Security.PermittedRoles", sec.PermittedRoles)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
sqProhibitedRoles, err := e.encodeRoleSlice(n, tt, "Security.ProhibitedRoles", sec.ProhibitedRoles)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
sqForcedRoles, err := e.encodeRoleSlice(n, tt, "Security.ForcedRoles", sec.ForcedRoles)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var impersonateUser string
|
||||
if _, ok := n.References["Security.ImpersonateUser.UserID"]; ok {
|
||||
usrRef := n.References["Security.ImpersonateUser.UserID"]
|
||||
node := tt.ParentForRef(n, usrRef)
|
||||
if node == nil {
|
||||
err = fmt.Errorf("invalid user reference %v: user does not exist", usrRef)
|
||||
return
|
||||
}
|
||||
impersonateUser = n.Identifiers.FriendlyIdentifier()
|
||||
}
|
||||
|
||||
return y7s.MakeMap(
|
||||
"impersonateUser", impersonateUser,
|
||||
"permittedRoles", sqPermittedRoles,
|
||||
"prohibitedRoles", sqProhibitedRoles,
|
||||
"forcedRoles", sqForcedRoles,
|
||||
)
|
||||
}
|
||||
|
||||
func (e YamlEncoder) encodeRoleSlice(n *envoyx.Node, tt envoyx.Traverser, k string, rr []string) (out *yaml.Node, err error) {
|
||||
sq, _ := y7s.MakeSeq()
|
||||
|
||||
for i := range rr {
|
||||
roleRef := n.References[fmt.Sprintf("%s.%d.RoleID", k, i)]
|
||||
node := tt.ParentForRef(n, roleRef)
|
||||
if node == nil {
|
||||
err = fmt.Errorf("invalid user reference %v: user does not exist", roleRef)
|
||||
return
|
||||
}
|
||||
|
||||
sq, err = y7s.AddSeq(sq, node.Identifiers.FriendlyIdentifier())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return sq, nil
|
||||
}
|
||||
Reference in New Issue
Block a user