mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 15:51:26 +00:00
services.traefik_labels (jsonb) holds operator-defined Traefik middlewares keyed 'middlewares.<name>.<type>[.<field>]', validated against an allowlist at write time. edgeLabels (extracted from createReplica) scopes each definition to the service router as <router>-<name> and auto-attaches it to the router's middleware chain after builtins. Router/service/provider-level keys are rejected. Surfaces: create/update API fields, services create/update --traefik-label (repeatable, key=value), MCP arg docs, OpenAPI + regenerated types, service-page Access editor (Routing overrides card + textarea). Also marks three stale ROADMAP2 items shipped: notification producers round-out, build-on-node (PR #60), mobile env/domains/scaling (PR #61). Generated with [Devin](https://devin.ai) Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
65 lines
2.2 KiB
Go
65 lines
2.2 KiB
Go
package api
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestNormalizeTraefikLabels(t *testing.T) {
|
|
valid := map[string]string{
|
|
"middlewares.rl.ratelimit.average": "100",
|
|
"middlewares.rl.ratelimit.period": "1m",
|
|
"middlewares.sec.headers.customrequestheaders.X-Frame-Options": "DENY",
|
|
"middlewares.gzip.compress": "true",
|
|
}
|
|
out, err := normalizeTraefikLabels(valid)
|
|
if err != nil {
|
|
t.Fatalf("valid labels rejected: %v", err)
|
|
}
|
|
if len(out) != len(valid) {
|
|
t.Fatalf("expected %d labels, got %d", len(valid), len(out))
|
|
}
|
|
if out["middlewares.gzip.compress"] != "true" {
|
|
t.Fatalf("flag-style middleware missing: %v", out)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeTraefikLabelsLowercasesType(t *testing.T) {
|
|
out, err := normalizeTraefikLabels(map[string]string{
|
|
"middlewares.rl.RateLimit.average": "10",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("mixed-case type rejected: %v", err)
|
|
}
|
|
if out["middlewares.rl.ratelimit.average"] != "10" {
|
|
t.Fatalf("type not lowercased: %v", out)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeTraefikLabelsRejects(t *testing.T) {
|
|
cases := map[string]string{
|
|
"traefik.enable": "true", // provider-level
|
|
"middlewares..ratelimit.average": "1", // empty name
|
|
"middlewares.x.evilinject.thing": "1", // unknown type
|
|
"routers.svc.rule": "x", // router hijack
|
|
"middlewares.x.ratelimit.average.bad\ninjection": "1", // control char in key fails regex
|
|
}
|
|
for k, v := range cases {
|
|
if _, err := normalizeTraefikLabels(map[string]string{k: v}); err == nil {
|
|
t.Fatalf("key %q should have been rejected", k)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNormalizeTraefikLabelsRejectsBadValues(t *testing.T) {
|
|
if _, err := normalizeTraefikLabels(map[string]string{"middlewares.a.ratelimit.average": ""}); err == nil {
|
|
t.Fatal("empty value accepted")
|
|
}
|
|
if _, err := normalizeTraefikLabels(map[string]string{"middlewares.a.ratelimit.average": strings.Repeat("x", 600)}); err == nil {
|
|
t.Fatal("oversized value accepted")
|
|
}
|
|
if _, err := normalizeTraefikLabels(map[string]string{"middlewares.a.ratelimit.average": "1\nmalicious"}); err == nil {
|
|
t.Fatal("newline value accepted")
|
|
}
|
|
}
|