feat: import agents_and_robots platform as unibots (Matrix-out, unibus transport)
Reemplaza el scaffold del echobot por la plataforma completa de bots traida desde ~/DataProyects/Github/agents_and_robots tras la operacion Matrix-out: los bots ya no hablan por Matrix sino por el bus unibus (modelo todo-rooms + E2E via shell/transportunibus sobre github.com/enmanuel/unibus/pkg/client). - go.mod: replace de unibus -> ../unibus y de fn-registry -> ../../../.. (paths relativos reajustados a la nueva ubicacion dentro de fn_registry). - app.md: bump a 0.2.0, descripcion + arquitectura + comandos + gotchas reales. - modulo Go conservado como github.com/enmanuel/agents (sin reescribir imports). agents_and_robots queda archivado como museo de la era Matrix.
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
package security_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
shellsecurity "github.com/enmanuel/agents/shell/security"
|
||||
)
|
||||
|
||||
// writeFile is a helper that creates a file in dir with the given content.
|
||||
func writeFile(t *testing.T, dir, name, content string) {
|
||||
t.Helper()
|
||||
if err := os.WriteFile(filepath.Join(dir, name), []byte(content), 0o644); err != nil {
|
||||
t.Fatalf("writeFile %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// --- Test 3.1: directorio inexistente → policy vacía, sin error ---
|
||||
|
||||
func TestLoad_NonExistentDir(t *testing.T) {
|
||||
policy, err := shellsecurity.Load("/tmp/does-not-exist-security-xyz")
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got: %v", err)
|
||||
}
|
||||
if len(policy.UserGroups) != 0 || len(policy.AgentGroups) != 0 || len(policy.Policies) != 0 {
|
||||
t.Errorf("expected empty policy, got: %+v", policy)
|
||||
}
|
||||
}
|
||||
|
||||
// --- Test 3.2: directorio vacío (sin YAML) → policy vacía, sin error ---
|
||||
|
||||
func TestLoad_EmptyDir(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
policy, err := shellsecurity.Load(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got: %v", err)
|
||||
}
|
||||
if len(policy.UserGroups) != 0 || len(policy.AgentGroups) != 0 || len(policy.Policies) != 0 {
|
||||
t.Errorf("expected empty policy, got: %+v", policy)
|
||||
}
|
||||
}
|
||||
|
||||
// --- Test 3.3: los 3 YAML válidos → policy con todos los campos ---
|
||||
|
||||
func TestLoad_AllFiles(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
writeFile(t, dir, "user-groups.yaml", `
|
||||
groups:
|
||||
admins:
|
||||
members: ["@admin:example.com"]
|
||||
everyone:
|
||||
members: ["*"]
|
||||
`)
|
||||
writeFile(t, dir, "agent-groups.yaml", `
|
||||
groups:
|
||||
assistants:
|
||||
agents:
|
||||
- assistant-bot
|
||||
all:
|
||||
agents: ["*"]
|
||||
`)
|
||||
writeFile(t, dir, "permissions.yaml", `
|
||||
policies:
|
||||
- agent_group: all
|
||||
permissions:
|
||||
- user_group: admins
|
||||
actions: ["*"]
|
||||
- user_group: everyone
|
||||
actions: ["ask"]
|
||||
`)
|
||||
|
||||
policy, err := shellsecurity.Load(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if len(policy.UserGroups) != 2 {
|
||||
t.Errorf("expected 2 user groups, got %d", len(policy.UserGroups))
|
||||
}
|
||||
if len(policy.AgentGroups) != 2 {
|
||||
t.Errorf("expected 2 agent groups, got %d", len(policy.AgentGroups))
|
||||
}
|
||||
if len(policy.Policies) != 1 {
|
||||
t.Errorf("expected 1 policy, got %d", len(policy.Policies))
|
||||
}
|
||||
if len(policy.Policies[0].Permissions) != 2 {
|
||||
t.Errorf("expected 2 permissions, got %d", len(policy.Policies[0].Permissions))
|
||||
}
|
||||
}
|
||||
|
||||
// --- Test 3.4: solo user-groups.yaml → user groups poblados, resto vacío ---
|
||||
|
||||
func TestLoad_OnlyUserGroups(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
writeFile(t, dir, "user-groups.yaml", `
|
||||
groups:
|
||||
admins:
|
||||
members: ["@admin:example.com"]
|
||||
`)
|
||||
|
||||
policy, err := shellsecurity.Load(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if len(policy.UserGroups) != 1 {
|
||||
t.Errorf("expected 1 user group, got %d", len(policy.UserGroups))
|
||||
}
|
||||
if policy.UserGroups[0].Name != "admins" {
|
||||
t.Errorf("expected group name 'admins', got %q", policy.UserGroups[0].Name)
|
||||
}
|
||||
if len(policy.AgentGroups) != 0 {
|
||||
t.Errorf("expected no agent groups, got %d", len(policy.AgentGroups))
|
||||
}
|
||||
if len(policy.Policies) != 0 {
|
||||
t.Errorf("expected no policies, got %d", len(policy.Policies))
|
||||
}
|
||||
}
|
||||
|
||||
// --- Test 3.5: YAML malformado → error con nombre de archivo en el mensaje ---
|
||||
|
||||
func TestLoad_MalformedYAML(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
writeFile(t, dir, "user-groups.yaml", `this: is: not: valid: yaml: [`)
|
||||
|
||||
_, err := shellsecurity.Load(dir)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for malformed YAML, got nil")
|
||||
}
|
||||
if got := err.Error(); len(got) == 0 {
|
||||
t.Fatal("error message is empty")
|
||||
}
|
||||
// Must mention the filename
|
||||
if !containsString(err.Error(), "user-groups.yaml") {
|
||||
t.Errorf("error message should contain filename, got: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// --- Test 3.6: "*" como string literal en members y agents ---
|
||||
|
||||
func TestLoad_WildcardStrings(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
writeFile(t, dir, "user-groups.yaml", `
|
||||
groups:
|
||||
everyone:
|
||||
members: ["*"]
|
||||
`)
|
||||
writeFile(t, dir, "agent-groups.yaml", `
|
||||
groups:
|
||||
all:
|
||||
agents: ["*"]
|
||||
`)
|
||||
|
||||
policy, err := shellsecurity.Load(dir)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if len(policy.UserGroups) != 1 {
|
||||
t.Fatalf("expected 1 user group, got %d", len(policy.UserGroups))
|
||||
}
|
||||
if len(policy.UserGroups[0].Members) != 1 || policy.UserGroups[0].Members[0] != "*" {
|
||||
t.Errorf("expected members=[\"*\"], got %v", policy.UserGroups[0].Members)
|
||||
}
|
||||
|
||||
if len(policy.AgentGroups) != 1 {
|
||||
t.Fatalf("expected 1 agent group, got %d", len(policy.AgentGroups))
|
||||
}
|
||||
if len(policy.AgentGroups[0].Agents) != 1 || policy.AgentGroups[0].Agents[0] != "*" {
|
||||
t.Errorf("expected agents=[\"*\"], got %v", policy.AgentGroups[0].Agents)
|
||||
}
|
||||
}
|
||||
|
||||
func containsString(s, sub string) bool {
|
||||
return len(s) >= len(sub) && (s == sub || len(s) > 0 && containsSubstr(s, sub))
|
||||
}
|
||||
|
||||
func containsSubstr(s, sub string) bool {
|
||||
for i := 0; i <= len(s)-len(sub); i++ {
|
||||
if s[i:i+len(sub)] == sub {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user