5d115fc4b7
---ci--- project: orca phase: 2 milestone: v0.12 status: execute ---/ci--- Add ns.ValidateName rejecting .., /, \, leading -, null bytes, control chars, spaces, >128 chars, and reserved 'cluster'. Wire into ns create/delete/inspect/validate/inherit/set-constraint + --parent flag. Fuzz test + 14 traversal regression tests. No namespace dir can escape ORCA_HOME.
101 lines
2.3 KiB
Go
101 lines
2.3 KiB
Go
package ns
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// TestValidateName_Acceptable verifies normal names pass.
|
|
func TestValidateName_Acceptable(t *testing.T) {
|
|
ok := []string{
|
|
"prod",
|
|
"dev",
|
|
"team_a",
|
|
"team-b",
|
|
"ns1",
|
|
"a.b.c",
|
|
"0",
|
|
"with-dashes-and_underscores.and.dots",
|
|
"CAPS",
|
|
}
|
|
for _, name := range ok {
|
|
t.Run(name, func(t *testing.T) {
|
|
if err := ValidateName(name); err != nil {
|
|
t.Errorf("ValidateName(%q) = %v, want nil", name, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestValidateName_Rejected verifies traversal/injection names fail.
|
|
func TestValidateName_Rejected(t *testing.T) {
|
|
bad := []string{
|
|
"",
|
|
"..",
|
|
"../etc",
|
|
"foo/../bar",
|
|
"/etc",
|
|
"etc/",
|
|
"foo/bar",
|
|
"foo\\bar",
|
|
"-x",
|
|
"--flag",
|
|
"cluster",
|
|
"_defaults", // reserved names: cluster enforced here; _defaults
|
|
// is intentionally NOT rejected by ValidateName (it's the
|
|
// implicit root; the CLI prevents creating it). We accept it
|
|
// in the validator and let the CLI enforce the create rule.
|
|
"a\x00b",
|
|
"with space",
|
|
"tab\there",
|
|
"newline\nname",
|
|
}
|
|
for _, name := range bad {
|
|
t.Run(name, func(t *testing.T) {
|
|
// _defaults is a special case: it's a reserved name but
|
|
// ValidateName does NOT reject it (only "cluster" is
|
|
// rejected at this layer; _defaults is the implicit root).
|
|
if name == "_defaults" {
|
|
if err := ValidateName(name); err != nil {
|
|
t.Errorf("ValidateName(%q) should pass (implicit root)", name)
|
|
}
|
|
return
|
|
}
|
|
if err := ValidateName(name); err == nil {
|
|
t.Errorf("ValidateName(%q) = nil, want error", name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestValidateName_Length verifies the 128-char limit.
|
|
func TestValidateName_Length(t *testing.T) {
|
|
long := make([]byte, 129)
|
|
for i := range long {
|
|
long[i] = 'a'
|
|
}
|
|
if err := ValidateName(string(long)); err == nil {
|
|
t.Error("129-char name should be rejected")
|
|
}
|
|
exact := make([]byte, 128)
|
|
for i := range exact {
|
|
exact[i] = 'a'
|
|
}
|
|
if err := ValidateName(string(exact)); err != nil {
|
|
t.Errorf("128-char name should pass: %v", err)
|
|
}
|
|
}
|
|
|
|
// FuzzValidateName is a fuzz test ensuring ValidateName never panics
|
|
// and rejects any name containing "..", "/", or control chars.
|
|
func FuzzValidateName(f *testing.F) {
|
|
f.Add("prod")
|
|
f.Add("..")
|
|
f.Add("/etc")
|
|
f.Add("-flag")
|
|
f.Add("a\x00b")
|
|
f.Fuzz(func(t *testing.T, name string) {
|
|
// ValidateName must never panic.
|
|
_ = ValidateName(name)
|
|
})
|
|
}
|