Files
capsule/pkg/template/reference_context.go
Oliver Bähler a6b830b1af feat: add ruleset api(#1844)
* fix(controller): decode old object for delete requests

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: modernize golang

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: modernize golang

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: modernize golang

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* fix(config): remove usergroups default

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* fix(config): remove usergroups default

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* sec(ghsa-2ww6-hf35-mfjm): intercept namespace subresource

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* feat(api): add rulestatus api

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: conflicts

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: conflicts

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: conflicts

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: conflicts

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: conflicts

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: conflicts

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: conflicts

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: conflicts

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: conflicts

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: conflicts

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* chore: conflicts

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* feat(api): add rulestatus api

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* feat(api): add rulestatus api

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* feat(api): add rulestatus api

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* feat(api): add rulestatus api

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* feat(api): add rulestatus api

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

* feat(api): add rulestatus api

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>

---------

Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
2026-01-27 14:28:48 +01:00

131 lines
3.1 KiB
Go

// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0
package template
import (
"bytes"
"context"
"encoding/json"
"fmt"
"strconv"
"text/template"
k8smeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/labels"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/projectcapsule/capsule/pkg/runtime/sanitize"
)
// Additional Context to enhance templating
// +kubebuilder:object:generate=true
type TemplateContext struct {
Resources []*TemplateResourceReference `json:"resources,omitempty"`
}
// +kubebuilder:object:generate=true
type TemplateResourceReference struct {
ResourceReference `json:",inline"`
// Index to mount the resource in the template context
Index string `json:"index,omitempty"`
}
func (t *TemplateContext) GatherContext(
ctx context.Context,
kubeClient client.Client,
restMapper k8smeta.RESTMapper,
data map[string]any,
namespace string,
additionSelectors []labels.Selector,
) (context ReferenceContext, errors []error) {
context = ReferenceContext{}
if t.Resources == nil {
return
}
// Template Context for Tenant
if len(data) != 0 {
if err := t.selfTemplate(data); err != nil {
return context, []error{fmt.Errorf("cloud not template: %w", err)}
}
}
// Load external Resources
for index, resource := range t.Resources {
res, err := resource.LoadResources(ctx, kubeClient, restMapper, namespace, additionSelectors, map[string]string{}, true)
if err != nil {
errors = append(errors, err)
continue
}
if len(res) > 0 {
resourceIndex := resource.Index
if resourceIndex == "" {
resourceIndex = strconv.Itoa(index)
}
for _, u := range res {
sanitize.SanitizeUnstructured(u, sanitize.DefaultSanitizeOptions())
}
context[resourceIndex] = res
}
}
return
}
// Templates itself with the option to populate tenant fields.
func (t *TemplateContext) selfTemplate(
data map[string]any,
) (err error) {
dataBytes, err := json.Marshal(t)
if err != nil {
return fmt.Errorf("error marshaling TemplateContext: %w", err)
}
if err := json.Unmarshal(dataBytes, &data); err != nil {
return fmt.Errorf("error unmarshaling TemplateContext into map: %w", err)
}
tmpl, err := template.New("tpl").Option("missingkey=error").Funcs(ExtraFuncMap()).Parse(string(dataBytes))
if err != nil {
return fmt.Errorf("error parsing template: %w", err)
}
var rendered bytes.Buffer
if err := tmpl.Execute(&rendered, data); err != nil {
return fmt.Errorf("error executing template: %w", err)
}
tplContext := &TemplateContext{}
if err := json.Unmarshal(rendered.Bytes(), tplContext); err != nil {
return fmt.Errorf("error unmarshaling JSON into TemplateContext: %w", err)
}
// Reassing templated context
*t = *tplContext
return nil
}
// +kubebuilder:object:generate=false
type ReferenceContext map[string]any
func (t *ReferenceContext) String() (string, error) {
dataBytes, err := json.Marshal(t)
if err != nil {
return "", fmt.Errorf("error marshaling TemplateContext: %w", err)
}
if err := json.Unmarshal(dataBytes, t); err != nil {
return "", fmt.Errorf("error unmarshaling TemplateContext into map: %w", err)
}
return string(dataBytes), nil
}